Index: conf/files
===================================================================
RCS file: /home/ncvs/src/sys/conf/files,v
retrieving revision 1.940
diff -u -p -r1.940 files
--- conf/files	13 Aug 2004 09:40:57 -0000	1.940
+++ conf/files	13 Aug 2004 21:18:04 -0000
@@ -1482,9 +1482,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	13 Aug 2004 21:18:04 -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.81
diff -u -p -r1.81 bridge.c
--- net/bridge.c	5 Jul 2004 16:28:31 -0000	1.81
+++ net/bridge.c	13 Aug 2004 21:18:05 -0000
@@ -964,16 +964,9 @@ 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 && (
-#ifdef PFIL_HOOKS
-	(inet_pfil_hook.ph_busy_count >= 0 && bdg_ipf != 0) ||
-#endif
-	(IPFW_LOADED && bdg_ipfw != 0))) {
-
-	int i;
+    if (src != NULL) {
+	int error, 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.
@@ -989,104 +982,14 @@ 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
-	 * places.  To deal with this we copy the header to a temporary
-	 * location, strip the header, and restore it as needed.
-	 */
-	bcopy(eh, &save_eh, ETHER_HDR_LEN);	/* local copy for restore */
-	m_adj(m0, ETHER_HDR_LEN);		/* temporarily strip header */
-
 #ifdef PFIL_HOOKS
-	/*
-	 * NetBSD-style generic packet filter, pfil(9), hooks.
-	 * Enables ipf(8) in bridging.
-	 */
-	if (inet_pfil_hook.ph_busy_count >= 0 &&
-	    m0->m_pkthdr.len >= sizeof(struct ip) &&
-	    ntohs(save_eh.ether_type) == ETHERTYPE_IP) {
-	    /*
-	     * before calling the firewall, swap fields the same as IP does.
-	     * here we assume the pkt is an IP one and the header is contiguous
-	     */
-	    struct ip *ip = mtod(m0, struct ip *);
-
-	    ip->ip_len = ntohs(ip->ip_len);
-	    ip->ip_off = ntohs(ip->ip_off);
-
-	    if (pfil_run_hooks(&inet_pfil_hook, &m0, src, PFIL_IN) != 0) {
-		/* NB: hook should consume packet */
-		return NULL;
-	    }
-	    if (m0 == NULL)			/* consumed by filter */
+	error = pfil_run_hooks(&ether_pfil_hook, &m0, m0->m_pkthdr.rcvif, PFIL_IN);
+	if (error != 0 || m == NULL)
 		return m0;
-	    /*
-	     * If we get here, the firewall has passed the pkt, but the mbuf
-	     * pointer might have changed. Restore ip and the fields ntohs()'d.
-	     */
-	    ip = mtod(m0, struct ip *);
-	    ip->ip_len = htons(ip->ip_len);
-	    ip->ip_off = htons(ip->ip_off);
-	}
 #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.
-	 */
-	bdg_ipfw_drops++;
-	return m0;
     }
 forward:
+
     /*
      * Again, bring up the headers in case of shared bufs to avoid
      * corruptions in the future.
Index: net/if_atmsubr.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_atmsubr.c,v
retrieving revision 1.35
diff -u -p -r1.35 if_atmsubr.c
--- net/if_atmsubr.c	25 Apr 2004 09:24:51 -0000	1.35
+++ net/if_atmsubr.c	13 Aug 2004 21:18:05 -0000
@@ -475,10 +475,26 @@ atm_getvccs(struct atmio_vcc **table, u_
 void
 atm_event(struct ifnet *ifp, u_int event, void *arg)
 {
+	int link_state;
+	struct atmev_ifstate_changed aifc;
+
 	if (ng_atm_event_p != NULL)
 		(*ng_atm_event_p)(ifp, event, arg);
 	if (atm_harp_event_p != NULL)
 		(*atm_harp_event_p)(ifp, event, arg);
+	if (event == ATMEV_IFSTATE_CHANGED) {
+		aifc = (atmev_ifstate_changed *)arg;
+
+		if (aifc->running && aifc->carrier)
+			link_state = LINK_STATE_UP;
+		else
+			link_state = LINK_STATE_DOWN;
+
+		if (ifp->if_link_state != link_state) {
+			ifp->if_link_state = link_state;
+			rt_ifmsg(ifp);
+		}
+	}
 }
 
 static moduledata_t atm_mod = {
Index: net/if_disc.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_disc.c,v
retrieving revision 1.44
diff -u -p -r1.44 if_disc.c
--- net/if_disc.c	15 Jul 2004 08:26:06 -0000	1.44
+++ net/if_disc.c	13 Aug 2004 21:18:05 -0000
@@ -193,6 +193,13 @@ discoutput(struct ifnet *ifp, struct mbu
 	ifp->if_opackets++;
 	ifp->if_obytes += m->m_pkthdr.len;
 
+	/*
+	if (ifp->if_flags & IFF_LINK0 && dst->sa_family == AF_INET) {
+		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, NULL);
+		return 0;
+	}
+	*/
+
 	m_freem(m);
 	return (0);
 }
Index: net/if_ethersubr.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.177
diff -u -p -r1.177 if_ethersubr.c
--- net/if_ethersubr.c	27 Jul 2004 23:20:45 -0000	1.177
+++ net/if_ethersubr.c	13 Aug 2004 21:18:05 -0000
@@ -117,11 +117,9 @@ static	int ether_resolvemulti(struct ifn
 
 #define senderr(e) do { error = (e); goto bad;} while (0)
 
-#if defined(INET) || defined(INET6)
-int
-ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst,
-	struct ip_fw **rule, int shared);
-static int ether_ipfw;
+#ifdef PFIL_HOOKS
+struct	pfil_head ether_pfil_hook;
+int	pfil_ether_init;
 #endif
 
 /*
@@ -358,17 +356,12 @@ ether_output_frame(struct ifnet *ifp, st
 			m_freem(m);
 		return (0);
 	}
-#if defined(INET) || defined(INET6)
-	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 */
-		}
-	}
-#endif
+
+#ifdef PFIL_HOOKS
+	error = pfil_run_hooks(&ether_pfil_hook, &m, ifp, PFIL_OUT);
+	if (error != 0 || m == NULL)
+		return (error);
+#endif /* PFIL_HOOKS */
 
 	/*
 	 * Queue message on interface, update output statistics if
@@ -378,102 +371,6 @@ ether_output_frame(struct ifnet *ifp, st
 	return (error);
 }
 
-#if defined(INET) || defined(INET6)
-/*
- * 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;
-}
-#endif
-
 /*
  * Process a received Ethernet packet; the packet is in the
  * mbuf chain m with the ethernet header at the front.
@@ -635,6 +532,9 @@ ether_demux(struct ifnet *ifp, struct mb
 #if defined(INET) || defined(INET6)
 	struct ip_fw *rule = ip_dn_claim_rule(m);
 #endif
+#ifdef PFIL_HOOKS
+	int error;
+#endif
 
 	KASSERT(ifp != NULL, ("ether_demux: NULL interface pointer"));
 
@@ -687,15 +587,14 @@ ether_demux(struct ifnet *ifp, struct mb
 
 #if defined(INET) || defined(INET6)
 post_stats:
-	if (IPFW_LOADED && ether_ipfw != 0) {
-		if (ether_ipfw_chk(&m, NULL, &rule, 0) == 0) {
-			if (m)
-				m_freem(m);
-			return;
-		}
-	}
 #endif
 
+#ifdef PFIL_HOOKS
+	error = pfil_run_hooks(&ether_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN);
+	if (error != 0 || m == NULL)
+		return;
+#endif /* PFIL_HOOKS */
+
 	/*
 	 * If VLANs are configured on the interface, check to
 	 * see if the device performed the decapsulation and
@@ -851,6 +750,18 @@ ether_ifattach(struct ifnet *ifp, const 
 	struct ifaddr *ifa;
 	struct sockaddr_dl *sdl;
 
+#ifdef PFIL_HOOKS
+	if (!pfil_ether_init) {
+		ether_pfil_hook.ph_type = PFIL_TYPE_AF;
+		ether_pfil_hook.ph_af = AF_ETHER;
+		if ((i = pfil_head_register(&ether_pfil_hook)) != 0)
+			printf("%s: WARNING: unable to register pfil hook, "
+				"error %d\n", __func__, i);
+		else
+			pfil_ether_init = 1;
+	}
+#endif /* PFIL_HOOKS */
+
 	ifp->if_type = IFT_ETHER;
 	ifp->if_addrlen = ETHER_ADDR_LEN;
 	ifp->if_hdrlen = ETHER_HDR_LEN;
@@ -908,10 +819,6 @@ ether_ifdetach(struct ifnet *ifp)
 
 SYSCTL_DECL(_net_link);
 SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet");
-#if defined(INET) || defined(INET6)
-SYSCTL_INT(_net_link_ether, OID_AUTO, ipfw, CTLFLAG_RW,
-	    &ether_ipfw,0,"Pass ether pkts through firewall");
-#endif
 
 #if 0
 /*
Index: netgraph/ng_bridge.c
===================================================================
RCS file: /home/ncvs/src/sys/netgraph/ng_bridge.c,v
retrieving revision 1.27
diff -u -p -r1.27 ng_bridge.c
--- netgraph/ng_bridge.c	20 Jul 2004 17:15:37 -0000	1.27
+++ netgraph/ng_bridge.c	13 Aug 2004 21:18:05 -0000
@@ -628,10 +628,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.46
diff -u -p -r1.46 igmp.c
--- netinet/igmp.c	11 Jun 2004 03:42:37 -0000	1.46
+++ netinet/igmp.c	13 Aug 2004 21:18:05 -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_divert.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_divert.c,v
retrieving revision 1.97
diff -u -p -r1.97 ip_divert.c
--- netinet/ip_divert.c	11 Aug 2004 20:30:08 -0000	1.97
+++ netinet/ip_divert.c	13 Aug 2004 21:18:05 -0000
@@ -373,27 +373,6 @@ cantsend:
 	return error;
 }
 
-/*
- * Return a copy of the specified packet, but without
- * the divert tag.  This is used when packets are ``tee'd''
- * and we want the cloned copy to not have divert processing.
- */
-struct mbuf *
-divert_clone(struct mbuf *m)
-{
-	struct mbuf *clone;
-	struct m_tag *mtag;
-
-	clone = m_dup(m, M_DONTWAIT);
-	if (clone != NULL) {
-		/* strip divert tag from copy */
-		mtag = m_tag_find(clone, PACKET_TAG_DIVERT, NULL);
-		if (mtag != NULL)
-			m_tag_delete(clone, mtag);
-	}
-	return clone;
-}
-
 static int
 div_attach(struct socket *so, int proto, struct thread *td)
 {
Index: netinet/ip_dummynet.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_dummynet.c,v
retrieving revision 1.82
diff -u -p -r1.82 ip_dummynet.c
--- netinet/ip_dummynet.c	15 Jul 2004 08:26:07 -0000	1.82
+++ netinet/ip_dummynet.c	13 Aug 2004 21:18:05 -0000
@@ -179,7 +179,6 @@ static struct mtx dummynet_mtx;
 static int config_pipe(struct dn_pipe *p);
 static int ip_dn_ctl(struct sockopt *sopt);
 
-static void rt_unref(struct rtentry *, const char *);
 static void dummynet(void *);
 static void dummynet_flush(void);
 void dummynet_drain(void);
@@ -188,19 +187,6 @@ static void dn_rule_delete(void *);
 
 int if_tx_rdy(struct ifnet *ifp);
 
-static void
-rt_unref(struct rtentry *rt, const char *where)
-{
-    if (rt == NULL)
-	return ;
-    RT_LOCK(rt);
-    if (rt->rt_refcnt <= 0) {
-	printf("dummynet: warning, refcnt now %ld, decreasing (%s)\n",
-	    rt->rt_refcnt, where);
-    }
-    RTFREE_LOCKED(rt);
-}
-
 /*
  * Heap management functions.
  *
@@ -446,6 +432,7 @@ transmit_event(struct dn_pipe *pipe)
 {
     struct mbuf *m ;
     struct dn_pkt_tag *pkt ;
+    struct ip *ip;
 
     DUMMYNET_LOCK_ASSERT();
 
@@ -468,6 +455,9 @@ transmit_event(struct dn_pipe *pipe)
 	    break ;
 
 	case DN_TO_IP_IN :
+	    ip = mtod(m, struct ip *);
+	    ip->ip_len = htons(ip->ip_len);
+	    ip->ip_off = htons(ip->ip_off);
 	    ip_input(m) ;
 	    break ;
 
@@ -1127,8 +1117,6 @@ locate_flowset(int pipe_nr, struct ip_fw
  * ifp		the 'ifp' parameter from the caller.
  *		NULL in ip_input, destination interface in ip_output,
  *		real_dst in bdg_forward
- * ro		route parameter (only used in ip_output, NULL otherwise)
- * dst		destination address, only used by ip_output
  * rule		matching rule, in case of multiple passes
  * flags	flags from the caller, only used in ip_output
  *
@@ -1214,23 +1202,8 @@ dummynet_io(struct mbuf *m, int pipe_nr,
     pkt->dn_dir = dir ;
 
     pkt->ifp = fwa->oif;
-    if (dir == DN_TO_IP_OUT) {
-	/*
-	 * We need to copy *ro because for ICMP pkts (and maybe others)
-	 * the caller passed a pointer into the stack; dst might also be
-	 * a pointer into *ro so it needs to be updated.
-	 */
-	pkt->ro = *(fwa->ro);
-	if (pkt->ro.ro_rt) {
-	    RT_LOCK(pkt->ro.ro_rt);
-	    RT_ADDREF(pkt->ro.ro_rt) ;
-	    RT_UNLOCK(pkt->ro.ro_rt);
-	}
-	if (fwa->dst == (struct sockaddr_in *)&fwa->ro->ro_dst) /* dst points into ro */
-	    fwa->dst = (struct sockaddr_in *)&(pkt->ro.ro_dst) ;
-	pkt->dn_dst = fwa->dst;
+    if (dir == DN_TO_IP_OUT)
 	pkt->flags = fwa->flags;
-    }
     if (q->head == NULL)
 	q->head = m;
     else
@@ -1327,7 +1300,6 @@ dropit:
  * Doing this would probably save us the initial bzero of dn_pkt
  */
 #define	DN_FREE_PKT(_m) do {				\
-	rt_unref(dn_tag_get(_m)->ro.ro_rt, __func__);	\
 	m_freem(_m);					\
 } while (0)
 
@@ -2069,6 +2041,7 @@ dummynet_modevent(module_t mod, int type
 		    return EEXIST ;
 		}
 		ip_dn_init();
+		printf("DUMMYNET loaded\n");
 		break;
 
 	case MOD_UNLOAD:
Index: netinet/ip_dummynet.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_dummynet.h,v
retrieving revision 1.31
diff -u -p -r1.31 ip_dummynet.h
--- netinet/ip_dummynet.h	25 Feb 2004 19:55:28 -0000	1.31
+++ netinet/ip_dummynet.h	13 Aug 2004 21:18:05 -0000
@@ -127,8 +127,6 @@ struct dn_pkt_tag {
 
     dn_key output_time;		/* when the pkt is due for delivery	*/
     struct ifnet *ifp;		/* interface, for ip_output		*/
-    struct sockaddr_in *dn_dst ;
-    struct route ro;		/* route, for ip_output. MUST COPY	*/
     int flags ;			/* flags, for ip_output (IPv6 ?)	*/
 };
 #endif /* _KERNEL */
Index: netinet/ip_fastfwd.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fastfwd.c,v
retrieving revision 1.16
diff -u -p -r1.16 ip_fastfwd.c
--- netinet/ip_fastfwd.c	11 Aug 2004 12:32:10 -0000	1.16
+++ netinet/ip_fastfwd.c	13 Aug 2004 21:18:05 -0000
@@ -103,6 +103,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>
@@ -163,20 +164,15 @@ ip_fastforward(struct mbuf *m)
 {
 	struct ip *ip;
 	struct mbuf *m0 = NULL;
-#ifdef IPDIVERT
-	struct ip *tip;
-	struct mbuf *clone = NULL;
-#endif
 	struct route ro;
 	struct sockaddr_in *dst = NULL;
 	struct in_ifaddr *ia = NULL;
 	struct ifaddr *ifa = NULL;
 	struct ifnet *ifp;
-	struct ip_fw_args args;
 	struct in_addr odest, dest;
 	u_short sum, ip_len;
 	int error = 0;
-	int hlen, ipfw, mtu;
+	int hlen, mtu;
 
 	/*
 	 * Are we active and forwarding packets?
@@ -378,91 +374,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.s_addr = args.next_hop->sin_addr.s_addr;
-			goto passin;
-		}
-		/*
-		 * Let through or not?
-		 */
-		if (ipfw != 0)
-			goto drop;
-	}
-passin:
-	ip = mtod(m, struct ip *);	/* if m changed during fw processing */
-
-	/*
 	 * Destination address changed?
 	 */
 	if (odest.s_addr != dest.s_addr) {
@@ -529,88 +440,6 @@ passin:
 	ip = mtod(m, struct ip *);
 	dest.s_addr = ip->ip_dst.s_addr;
 #endif
-	if (fw_enable && IPFW_LOADED && !args.next_hop) {
-		bzero(&args, sizeof(args));
-		args.m = m;
-		args.oif = ifp;
-
-		ipfw = ip_fw_chk_ptr(&args);
-		m = args.m;
-
-		M_ASSERTVALID(m);
-		M_ASSERTPKTHDR(m);
-
-		if ((ipfw & IP_FW_PORT_DENY_FLAG) || m == NULL)
-			goto drop;
-
-		if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
-			/*
-			 * XXX note: if the ifp or rt entry are deleted
-			 * while a pkt is in dummynet, we are in trouble!
-			 */
-			args.ro = &ro;		/* dummynet does not save it */
-			args.dst = dst;
-
-			ip_dn_io_ptr(m, ipfw & 0xffff, DN_TO_IP_OUT, &args);
-			goto consumed;
-		}
-#ifdef IPDIVERT
-		if (ipfw != 0 && (ipfw & IP_FW_PORT_DYNT_FLAG) == 0) {
-			/*
-			 * See if this is a fragment
-			 */
-			if (ip->ip_off & (IP_MF | IP_OFFMASK))
-				goto droptoours;
-			/*
-			 * Tee packet
-			 */
-			if ((ipfw & IP_FW_PORT_TEE_FLAG) != 0)
-				clone = divert_clone(m);
-			else
-				clone = m;
-			if (clone == NULL)
-				goto passout;
-
-			/*
-			 * Delayed checksums are not compatible with divert
-			 */
-			if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
-				in_delayed_cksum(m);
-				m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
-			}
-			/*
-			 * Restore packet header fields to original values
-			 */
-			tip = mtod(m, struct ip *);
-			tip->ip_len = htons(tip->ip_len);
-			tip->ip_off = htons(tip->ip_off);
-			/*
-			 * Deliver packet to divert input routine
-			 */
-			divert_packet(m, 0);
-			/*
-			 * If this was not tee, we are done
-			 */
-			m = clone;
-			if ((ipfw & IP_FW_PORT_TEE_FLAG) == 0) {
-				goto consumed;
-			}
-			/* Continue if it was tee */
-			goto passout;
-		}
-#endif
-		if (ipfw == 0 && args.next_hop != NULL) {
-			dest.s_addr = args.next_hop->sin_addr.s_addr;
-			goto passout;
-		}
-		/*
-		 * Let through or not?
-		 */
-		if (ipfw != 0)
-			goto drop;
-	}
-passout:
-	ip = mtod(m, struct ip *);
 
 	/*
 	 * Destination address changed?
@@ -621,30 +450,11 @@ passout:
 		 */
 		if (in_localip(dest)) {
 forwardlocal:
-			if (args.next_hop) {
-				struct m_tag *mtag = m_tag_get(
-				    PACKET_TAG_IPFORWARD,
-				    sizeof(struct sockaddr_in *),
-				    M_NOWAIT);
-				if (mtag == NULL) {
-					goto drop;
-				}
-				*(struct sockaddr_in **)(mtag+1) =
-				    args.next_hop;
-				m_tag_prepend(m, mtag);
-			}
-#ifdef IPDIVERT
-droptoours:	/* Used for DIVERT */
-#endif
 			/* for ip_input */
 			m->m_flags |= M_FASTFWD_OURS;
 
-			/* ip still points to the real packet */
-			ip->ip_len = htons(ip->ip_len);
-			ip->ip_off = htons(ip->ip_off);
-
 			/*
-			 * Return packet for processing by ip_input
+			 * Return packet for processing by ip_input()
 			 */
 			if (ro.ro_rt)
 				RTFREE(ro.ro_rt);
Index: netinet/ip_fw.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fw.h,v
retrieving revision 1.87
diff -u -p -r1.87 ip_fw.h
--- netinet/ip_fw.h	12 Aug 2004 22:05:47 -0000	1.87
+++ netinet/ip_fw.h	13 Aug 2004 21:18:05 -0000
@@ -28,6 +28,9 @@
 #ifndef _IPFW2_H
 #define _IPFW2_H
 #define IPFW2  1
+
+#define IPFIREWALL_FORWARD
+
 /*
  * The kernel representation of ipfw rules is made of a list of
  * 'instructions' (for all practical purposes equivalent to BPF
@@ -420,8 +423,6 @@ struct ip_fw_args {
 	struct ip_fw	*rule;		/* matching rule		*/
 	struct ether_header *eh;	/* for bridged packets		*/
 
-	struct route	*ro;		/* for dummynet			*/
-	struct sockaddr_in *dst;	/* for dummynet			*/
 	int flags;			/* for dummynet			*/
 
 	struct ipfw_flow_id f_id;	/* grabbed from IP header	*/
@@ -436,15 +437,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.69
diff -u -p -r1.69 ip_fw2.c
--- netinet/ip_fw2.c	12 Aug 2004 22:05:47 -0000	1.69
+++ netinet/ip_fw2.c	13 Aug 2004 21:18:06 -0000
@@ -156,9 +156,6 @@ static int autoinc_step = 100; /* bounde
 
 #ifdef SYSCTL_NODE
 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, enable,
-    CTLFLAG_RW | CTLFLAG_SECURE3,
-    &fw_enable, 0, "Enable ipfw");
 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step, CTLFLAG_RW,
     &autoinc_step, 0, "Rule number autincrement step");
 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, one_pass,
@@ -276,10 +273,6 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dy
 #endif /* SYSCTL_NODE */
 
 
-static ip_fw_chk_t	ipfw_chk;
-
-ip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL;	/* hook into dummynet */
-
 /*
  * This macro maps an ip pointer into a layer3 header pointer of type T
  */
@@ -1653,7 +1646,7 @@ check_uidgid(ipfw_insn_u32 *insn,
  *		  16 bits as a dummynet pipe number instead of diverting
  */
 
-static int
+int
 ipfw_chk(struct ip_fw_args *args)
 {
 	/*
@@ -3406,7 +3399,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);
 
@@ -3420,7 +3412,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 */);
@@ -3441,7 +3432,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 {
@@ -3450,6 +3441,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.95
diff -u -p -r1.95 ip_icmp.c
--- netinet/ip_icmp.c	17 Jul 2004 05:10:05 -0000	1.95
+++ netinet/ip_icmp.c	13 Aug 2004 21:18:06 -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>
@@ -711,7 +712,7 @@ match:
 		 * add on any record-route or timestamp options.
 		 */
 		cp = (u_char *) (ip + 1);
-		if ((opts = ip_srcroute()) == 0 &&
+		if ((opts = ip_srcroute(m)) == 0 &&
 		    (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
 			opts->m_len = sizeof(struct in_addr);
 			mtod(opts, struct in_addr *)->s_addr = 0;
Index: netinet/ip_input.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.281
diff -u -p -r1.281 ip_input.c
--- netinet/ip_input.c	12 Aug 2004 08:37:42 -0000	1.281
+++ netinet/ip_input.c	13 Aug 2004 21:18:06 -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,44 +192,7 @@ 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.
- * XXX: Broken on SMP and possibly preemption!
- */
-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 *);
 
 /*
  * IP initialization: fill in IP protocol switch table.
@@ -299,13 +250,8 @@ ip_input(struct mbuf *m)
 	struct ip *ip = NULL;
 	struct in_ifaddr *ia = NULL;
 	struct ifaddr *ifa;
-	int    i, checkif, hlen = 0;
+	int    checkif, hlen = 0;
 	u_short sum;
-	struct in_addr pkt_dst;
-#ifdef IPDIVERT
-	u_int32_t divert_info;			/* packet divert/tee info */
-#endif
-	struct ip_fw_args args;
 	int dchg = 0;				/* dest changed after fw */
 #ifdef PFIL_HOOKS
 	struct in_addr odst;			/* original dst address */
@@ -317,26 +263,20 @@ ip_input(struct mbuf *m)
 	int s, error;
 #endif /* FAST_IPSEC */
 
-	args.eh = NULL;
-	args.oif = NULL;
-
   	M_ASSERTPKTHDR(m);
   	
-	args.next_hop = m_claim_next(m, PACKET_TAG_IPFORWARD);
-	args.rule = ip_dn_claim_rule(m);
-  
 	if (m->m_flags & M_FASTFWD_OURS) {
-		/* ip_fastforward firewall changed dest to local */
+		/*
+		 * ip_fastforward firewall changed dest to local
+		 * expect ip_len and ip_off in host byte order
+		 */
 		m->m_flags &= ~M_FASTFWD_OURS;	/* for reflected mbufs */
+		/* Set up some basic stuff */
+		ip = mtod(m, struct ip *);
+		hlen = ip->ip_hl << 2;
   		goto ours;
   	}
 
-  	if (args.rule) {	/* dummynet already filtered us */
-  		ip = mtod(m, struct ip *);
-  		hlen = ip->ip_hl << 2;
-		goto iphack ;
-	}
-
 	ipstat.ips_total++;
 
 	if (m->m_pkthdr.len < sizeof(struct ip))
@@ -439,20 +379,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.
@@ -462,55 +388,27 @@ 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;
+#ifdef IPFIREWALL_FORWARD
+	if (m->m_flags & M_FASTFWD_OURS) {
+		m->m_flags &= ~M_FASTFWD_OURS;
+		goto ours;
+	}
+	dchg = (m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL);
+#endif /* IPFIREWALL_FORWARD */
 
-		args.m = m;
-		i = ip_fw_chk_ptr(&args);
-		m = args.m;
+#endif /* PFIL_HOOKS */
 
-		if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */
-			if (m)
-				m_freem(m);
-			return;
-		}
-		ip = mtod(m, struct ip *); /* just in case m changed */
-		if (i == 0 && args.next_hop == NULL)	/* common case */
-			goto pass;
-                if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) {
-			/* Send packet to the appropriate pipe */
-			ip_dn_io_ptr(m, i&0xffff, DN_TO_IP_IN, &args);
-			return;
-		}
-#ifdef IPDIVERT
-		if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) {
-			/* Divert or tee packet */
-			goto ours;
-		}
-#endif
-		if (i == 0 && args.next_hop != NULL)
-			goto pass;
-		/*
-		 * if we get here, the packet must be dropped
-		 */
-		m_freem(m);
-		return;
-	}
+#if defined(FAST_IPSEC) && !defined(IPSEC_FILTERGIF)
 pass:
+#endif
 
 	/*
 	 * Process options and, if not destined for us,
@@ -518,8 +416,7 @@ pass:
 	 * error was detected (causing an icmp message
 	 * to be sent and the original packet to be freed).
 	 */
-	ip_nhops = 0;		/* for source routed packets */
-	if (hlen > sizeof (struct ip) && ip_dooptions(m, 0, args.next_hop))
+	if (hlen > sizeof (struct ip) && ip_dooptions(m, 0))
 		return;
 
         /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
@@ -542,12 +439,6 @@ pass:
 		goto ours;
 
 	/*
-	 * Cache the destination address of the packet; this may be
-	 * changed by use of 'ipfw fwd'.
-	 */
-	pkt_dst = args.next_hop ? args.next_hop->sin_addr : ip->ip_dst;
-
-	/*
 	 * Enable a consistency check between the destination address
 	 * and the arrival interface for a unicast packet (the RFC 1122
 	 * strong ES model) if IP forwarding is disabled and the packet
@@ -564,18 +455,18 @@ pass:
 	checkif = ip_checkinterface && (ipforwarding == 0) && 
 	    m->m_pkthdr.rcvif != NULL &&
 	    ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) &&
-	    (args.next_hop == NULL) && (dchg == 0);
+	    (dchg == 0);
 
 	/*
 	 * Check for exact addresses in the hash bucket.
 	 */
-	LIST_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) {
+	LIST_FOREACH(ia, INADDR_HASH(ip->ip_dst.s_addr), ia_hash) {
 		/*
 		 * If the address matches, verify that the packet
 		 * arrived via the correct interface if checking is
 		 * enabled.
 		 */
-		if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr && 
+		if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr && 
 		    (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif))
 			goto ours;
 	}
@@ -594,9 +485,9 @@ pass:
 				continue;
 			ia = ifatoia(ifa);
 			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
-			    pkt_dst.s_addr)
+			    ip->ip_dst.s_addr)
 				goto ours;
-			if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr)
+			if (ia->ia_netbroadcast.s_addr == ip->ip_dst.s_addr)
 				goto ours;
 #ifdef BOOTP_COMPAT
 			if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
@@ -704,7 +595,7 @@ pass:
 			goto bad;
 		}
 #endif /* FAST_IPSEC */
-		ip_forward(m, dchg, args.next_hop);
+		ip_forward(m, dchg);
 	}
 	return;
 
@@ -715,7 +606,7 @@ ours:
 	 * if the packet is destined for us.
 	 */
 	if (ipstealth && hlen > sizeof (struct ip) &&
-	    ip_dooptions(m, 1, args.next_hop))
+	    ip_dooptions(m, 1))
 		return;
 #endif /* IPSTEALTH */
 
@@ -736,20 +627,6 @@ ours:
 		ip = mtod(m, struct ip *);
 		/* Get the header length of the reassembled packet */
 		hlen = ip->ip_hl << 2;
-#ifdef IPDIVERT
-		/* Restore original checksum before diverting packet */
-		if (divert_find_info(m) != 0) {
-			ip->ip_len = htons(ip->ip_len);
-			ip->ip_off = htons(ip->ip_off);
-			ip->ip_sum = 0;
-			if (hlen == sizeof(struct ip))
-				ip->ip_sum = in_cksum_hdr(ip);
-			else
-				ip->ip_sum = in_cksum(m, hlen);
-			ip->ip_off = ntohs(ip->ip_off);
-			ip->ip_len = ntohs(ip->ip_len);
-		}
-#endif
 	}
 
 	/*
@@ -758,46 +635,6 @@ ours:
 	 */
 	ip->ip_len -= hlen;
 
-#ifdef IPDIVERT
-	/*
-	 * Divert or tee packet to the divert protocol if required.
-	 */
-	divert_info = divert_find_info(m);
-	if (divert_info != 0) {
-		struct mbuf *clone;
-
-		/* Clone packet if we're doing a 'tee' */
-		if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0)
-			clone = divert_clone(m);
-		else
-			clone = NULL;
-
-		/* Restore packet header fields to original values */
-		ip->ip_len += hlen;
-		ip->ip_len = htons(ip->ip_len);
-		ip->ip_off = htons(ip->ip_off);
-
-		/* Deliver packet to divert input routine */
-		divert_packet(m, 1);
-		ipstat.ips_delivered++;
-
-		/* If 'tee', continue with original packet */
-		if (clone == NULL)
-			return;
-		m = clone;
-		ip = mtod(m, struct ip *);
-		ip->ip_len += hlen;
-		/*
-		 * Jump backwards to complete processing of the
-		 * packet.  We do not need to clear args.next_hop
-		 * as that will not be used again and the cloned packet
-		 * doesn't contain a divert packet tag so we won't
-		 * re-entry this block.
-		 */
-		goto pass;
-	}
-#endif
-
 #ifdef IPSEC
 	/*
 	 * enforce IPsec policy checking if we are seeing last header.
@@ -854,15 +691,7 @@ DPRINTF(("ip_input: no SP, packet discar
 	 * Switch out to protocol's input routine.
 	 */
 	ipstat.ips_delivered++;
-	if (args.next_hop && ip->ip_p == IPPROTO_TCP) {
-		/* attach next hop info for TCP */
-		struct m_tag *mtag = m_tag_get(PACKET_TAG_IPFORWARD,
-		    sizeof(struct sockaddr_in *), M_NOWAIT);
-		if (mtag == NULL)
-			goto bad;
-		*(struct sockaddr_in **)(mtag+1) = args.next_hop;
-		m_tag_prepend(m, mtag);
-	}
+
 	(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
 	return;
 bad:
@@ -1090,18 +919,6 @@ found:
 
 inserted:
 
-#ifdef IPDIVERT
-	if (ip->ip_off != 0) {
-		/*
-		 * Strip any divert information; only the info
-		 * on the first fragment is used/kept.
-		 */
-		struct m_tag *mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL);
-		if (mtag)
-			m_tag_delete(m, mtag);
-	}
-#endif
-
 	/*
 	 * Check for complete reassembly and perform frag per packet
 	 * limiting.
@@ -1284,288 +1101,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 == NULL) {
-				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)) == NULL)
-				ia = (INA)ifa_ifwithnet((SA)&ipaddr);
-			} else
-				ia = ip_rtaddr(ipaddr.sin_addr);
-			if (ia == NULL) {
-				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)) == NULL &&
-			    (ia = ip_rtaddr(ipaddr.sin_addr)) == NULL) {
-				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 == NULL)
-					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) == NULL)
-					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.
  */
@@ -1592,126 +1127,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 == NULL)
-		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,
@@ -1735,35 +1150,32 @@ u_char inetctlerrmap[PRC_NCMDS] = {
  * The srcrt parameter indicates whether the packet is being forwarded
  * via a source route.
  */
-static void
-ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
+void
+ip_forward(struct mbuf *m, int srcrt)
 {
 	struct ip *ip = mtod(m, struct ip *);
 	struct in_ifaddr *ia;
 	int error, type = 0, code = 0;
 	struct mbuf *mcopy;
-	n_long dest;
-	struct in_addr pkt_dst;
+	struct in_addr dest;
 	struct ifnet *destifp;
 #if defined(IPSEC) || defined(FAST_IPSEC)
 	struct ifnet dummyifp;
 #endif
 
-	/*
-	 * Cache the destination address of the packet; this may be
-	 * changed by use of 'ipfw fwd'.
-	 */
-	pkt_dst = next_hop ? next_hop->sin_addr : ip->ip_dst;
+#ifdef IPFIREWALL_FORWARD
+	/* fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); */
+#endif
 
 #ifdef DIAGNOSTIC
 	if (ipprintfs)
 		printf("forward: src %lx dst %lx ttl %x\n",
-		    (u_long)ip->ip_src.s_addr, (u_long)pkt_dst.s_addr,
+		    (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr,
 		    ip->ip_ttl);
 #endif
 
 
-	if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(pkt_dst) == 0) {
+	if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {
 		ipstat.ips_cantforward++;
 		m_freem(m);
 		return;
@@ -1780,7 +1192,7 @@ ip_forward(struct mbuf *m, int srcrt, st
 	}
 #endif
 
-	if ((ia = ip_rtaddr(pkt_dst)) == NULL) {
+	if ((ia = ip_rtaddr(ip->ip_dst)) == NULL) {
 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
 		return;
 	}
@@ -1835,7 +1247,7 @@ ip_forward(struct mbuf *m, int srcrt, st
 	 * Also, don't send redirect if forwarding using a default route
 	 * or a route modified by a redirect.
 	 */
-	dest = 0;
+	dest.s_addr = 0;
 	if (ipsendredirects && ia->ia_ifp == m->m_pkthdr.rcvif) {
 		struct sockaddr_in *sin;
 		struct route ro;
@@ -1845,29 +1257,29 @@ ip_forward(struct mbuf *m, int srcrt, st
 		sin = (struct sockaddr_in *)&ro.ro_dst;
 		sin->sin_family = AF_INET;
 		sin->sin_len = sizeof(*sin);
-		sin->sin_addr = pkt_dst;
+		sin->sin_addr = ip->ip_dst;
 		rtalloc_ign(&ro, RTF_CLONING);
 
 		rt = ro.ro_rt;
 
 		if (rt && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
 		    satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
-		    ipsendredirects && !srcrt && !next_hop) {
+		    ipsendredirects && !srcrt) {
 #define	RTA(rt)	((struct in_ifaddr *)(rt->rt_ifa))
 			u_long src = ntohl(ip->ip_src.s_addr);
 
 			if (RTA(rt) &&
 			    (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
 				if (rt->rt_flags & RTF_GATEWAY)
-					dest = satosin(rt->rt_gateway)->sin_addr.s_addr;
+					dest.s_addr = satosin(rt->rt_gateway)->sin_addr.s_addr;
 				else
-					dest = pkt_dst.s_addr;
+					dest.s_addr = ip->ip_dst.s_addr;
 				/* Router requirements says to only send host redirects */
 				type = ICMP_REDIRECT;
 				code = ICMP_REDIRECT_HOST;
 #ifdef DIAGNOSTIC
 				if (ipprintfs)
-					printf("redirect (%d) to %lx\n", code, (u_long)dest);
+					printf("redirect (%d) to %lx\n", code, (u_long)dest.s_addr);
 #endif
 			}
 		}
@@ -1875,16 +1287,6 @@ ip_forward(struct mbuf *m, int srcrt, st
 			RTFREE(rt);
 	}
 
-	if (next_hop) {
-		struct m_tag *mtag = m_tag_get(PACKET_TAG_IPFORWARD,
-		    sizeof(struct sockaddr_in *), M_NOWAIT);
-		if (mtag == NULL) {
-			m_freem(m);
-			return;
-		}
-		*(struct sockaddr_in **)(mtag+1) = next_hop;
-		m_tag_prepend(m, mtag);
-	}
 	error = ip_output(m, (struct mbuf *)0, NULL, IP_FORWARDING, 0, NULL);
 	if (error)
 		ipstat.ips_cantforward++;
@@ -2012,7 +1414,7 @@ ip_forward(struct mbuf *m, int srcrt, st
 		m_freem(mcopy);
 		return;
 	}
-	icmp_error(mcopy, type, code, dest, destifp);
+	icmp_error(mcopy, type, code, dest.s_addr, destifp);
 }
 
 void
@@ -2068,7 +1470,7 @@ ip_savecontrol(inp, mp, ip, m)
 	}
 	/* ip_srcroute doesn't do what we want here, need to fix */
 	if (inp->inp_flags & INP_RECVRETOPTS) {
-		*mp = sbcreatecontrol((caddr_t) ip_srcroute(),
+		*mp = sbcreatecontrol((caddr_t) ip_srcroute(m),
 		    sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP);
 		if (*mp)
 			mp = &(*mp)->m_next;
Index: netinet/ip_mroute.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_mroute.c,v
retrieving revision 1.104
diff -u -p -r1.104 ip_mroute.c
--- netinet/ip_mroute.c	3 Aug 2004 02:01:44 -0000	1.104
+++ netinet/ip_mroute.c	13 Aug 2004 21:18:06 -0000
@@ -55,6 +55,7 @@
 #include <netinet/ip.h>
 #include <netinet/ip_encap.h>
 #include <netinet/ip_mroute.h>
+#include <netinet/ip_options.h>
 #include <netinet/ip_var.h>
 #ifdef PIM
 #include <netinet/pim.h>
Index: netinet/ip_output.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.223
diff -u -p -r1.223 ip_output.c
--- netinet/ip_output.c	11 Aug 2004 10:46:15 -0000	1.223
+++ netinet/ip_output.c	13 Aug 2004 21:18:06 -0000
@@ -52,6 +52,7 @@
 #include <sys/sysctl.h>
 
 #include <net/if.h>
+#include <net/netisr.h>
 #include <net/route.h>
 
 #include <netinet/in.h>
@@ -60,6 +61,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 +105,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,49 +132,27 @@ ip_output(struct mbuf *m, struct mbuf *o
 	struct ifnet *ifp = NULL;	/* keep compiler happy */
 	struct mbuf *m0;
 	int hlen = sizeof (struct ip);
-	int len, off, error = 0;
+	int len, error = 0;
 	struct sockaddr_in *dst = NULL;	/* keep compiler happy */
 	struct in_ifaddr *ia = NULL;
 	int isbroadcast, sw_csum;
-	struct in_addr pkt_dst;
 	struct route iproute;
-	struct m_tag *mtag, *dummytag;
+	struct in_addr odst;
+#ifdef IPFIREWALL_FORWARD
+	struct m_tag *fwd_tag = NULL;
+#endif
 #ifdef IPSEC
 	struct secpolicy *sp = NULL;
 #endif
 #ifdef FAST_IPSEC
 	struct secpolicy *sp = NULL;
 	struct tdb_ident *tdbi;
+	struct m_tag *mtag;
 	int s;
 #endif /* FAST_IPSEC */
-	struct ip_fw_args args;
-	int src_was_INADDR_ANY = 0;	/* as the name says... */
-
-	args.eh = NULL;
-	args.rule = NULL;
 
 	M_ASSERTPKTHDR(m);
 	
-	args.next_hop = m_claim_next(m, PACKET_TAG_IPFORWARD);
-	dummytag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
-	if (dummytag != NULL) {
-		struct dn_pkt_tag *dt = (struct dn_pkt_tag *)(dummytag+1);
-		/*
-		 * Prevent lower layers from finding the tag
-		 * Cleanup and free is done below
-		 */
-		m_tag_unlink(m, dummytag);
-		/*
-		 * the packet was already tagged, so part of the
-		 * processing was already done, and we need to go down.
-		 * Get parameters from the header.
-		 */
-		args.rule = dt->rule;
-		ro = &(dt->ro);
-		dst = dt->dn_dst;
-		ifp = dt->ifp;
-	}
-
 	if (ro == NULL) {
 		ro = &iproute;
 		bzero(ro, sizeof (*ro));
@@ -185,14 +161,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 +168,6 @@ ip_output(struct mbuf *m, struct mbuf *o
 			hlen = len;
 	}
 	ip = mtod(m, struct ip *);
-	pkt_dst = args.next_hop ? args.next_hop->sin_addr : ip->ip_dst;
 
 	/*
 	 * Fill in IP header.  If we are not allowing fragmentation,
@@ -227,6 +194,7 @@ ip_output(struct mbuf *m, struct mbuf *o
 	}
 
 	dst = (struct sockaddr_in *)&ro->ro_dst;
+again:
 	/*
 	 * If there is a cached route,
 	 * check that it is to the same destination
@@ -236,15 +204,19 @@ ip_output(struct mbuf *m, struct mbuf *o
 	 */
 	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
 			  dst->sin_family != AF_INET ||
-			  dst->sin_addr.s_addr != pkt_dst.s_addr)) {
+			  dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
 		RTFREE(ro->ro_rt);
 		ro->ro_rt = (struct rtentry *)0;
 	}
+#ifdef IPFIREWALL_FORWARD
+	if (ro->ro_rt == NULL && fwd_tag == NULL) {
+#else
 	if (ro->ro_rt == NULL) {
+#endif
 		bzero(dst, sizeof(*dst));
 		dst->sin_family = AF_INET;
 		dst->sin_len = sizeof(*dst);
-		dst->sin_addr = pkt_dst;
+		dst->sin_addr = ip->ip_dst;
 	}
 	/*
 	 * If routing to interface only,
@@ -292,7 +264,7 @@ ip_output(struct mbuf *m, struct mbuf *o
 		else
 			isbroadcast = in_broadcast(dst->sin_addr, ifp);
 	}
-	if (IN_MULTICAST(ntohl(pkt_dst.s_addr))) {
+	if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
 		struct in_multi *inm;
 
 		m->m_flags |= M_MCAST;
@@ -334,7 +306,7 @@ ip_output(struct mbuf *m, struct mbuf *o
 				ip->ip_src = IA_SIN(ia)->sin_addr;
 		}
 
-		IN_LOOKUP_MULTI(pkt_dst, ifp, inm);
+		IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
 		if (inm != NULL &&
 		   (imo == NULL || imo->imo_multicast_loop)) {
 			/*
@@ -389,7 +361,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,27 +372,8 @@ 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 */
-#ifdef ALTQ
-	/*
-	 * disable packet drop hack.
-	 * packetdrop should be done by queueing.
-	 */
-#else /* !ALTQ */
-	/*
-	 * Verify that we have any chance at all of being able to queue
-	 *      the packet or packet fragments
-	 */
-	if ((ifp->if_snd.ifq_len + ip->ip_len / ifp->if_mtu + 1) >=
-		ifp->if_snd.ifq_maxlen) {
-			error = ENOBUFS;
-			ipstat.ips_odropped++;
-			goto bad;
-	}
-#endif /* !ALTQ */
 
 	/*
 	 * Look for broadcast address and
@@ -698,250 +651,69 @@ skip_ipsec:
 spd_done:
 #endif /* FAST_IPSEC */
 
-	/*
-	 * IpHack's section.
-	 * - Xlate: translate packet's addr/port (NAT).
-	 * - Firewall: deny/allow/etc.
-	 * - Wrap: fake packet's addr/port <unimpl.>
-	 * - Encapsulate: put it in another IP and send out. <unimp.>
-	 */ 
 #ifdef PFIL_HOOKS
 	/*
 	 * Run through list of hooks for output packets.
 	 */
+	odst.s_addr = ip->ip_dst.s_addr;
 	error = pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT);
 	if (error != 0 || m == NULL)
 		goto done;
+
 	ip = mtod(m, struct ip *);
-#endif /* PFIL_HOOKS */
 
-	/*
-	 * Check with the firewall...
-	 * but not if we are already being fwd'd from a firewall.
-	 */
-	if (fw_enable && IPFW_LOADED && !args.next_hop) {
-		struct sockaddr_in *old = dst;
+	/* See if destination IP address was changed by packet filter. */
+	if (odst.s_addr != ip->ip_dst.s_addr) {
+		m->m_flags |= M_SKIP_FIREWALL;
+		if (in_localip(ip->ip_dst)) {
+			m->m_flags |= M_FASTFWD_OURS;
+			if (m->m_pkthdr.rcvif == NULL)
+				m->m_pkthdr.rcvif = ifunit("lo0");
+			if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
+				m->m_pkthdr.csum_flags |=
+				    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+				m->m_pkthdr.csum_data = 0xffff;
+			}
+			m->m_pkthdr.csum_flags |=
+			    CSUM_IP_CHECKED | CSUM_IP_VALID;
 
-		args.m = m;
-		args.next_hop = dst;
-		args.oif = ifp;
-		off = ip_fw_chk_ptr(&args);
-		m = args.m;
-		dst = args.next_hop;
-
-                /*
-		 * On return we must do the following:
-		 * m == NULL	-> drop the pkt (old interface, deprecated)
-		 * (off & IP_FW_PORT_DENY_FLAG)	-> drop the pkt (new interface)
-		 * 1<=off<= 0xffff		-> DIVERT
-		 * (off & IP_FW_PORT_DYNT_FLAG)	-> send to a DUMMYNET pipe
-		 * (off & IP_FW_PORT_TEE_FLAG)	-> TEE the packet
-		 * dst != old			-> IPFIREWALL_FORWARD
-		 * off==0, dst==old		-> accept
-		 * If some of the above modules are not compiled in, then
-		 * we should't have to check the corresponding condition
-		 * (because the ipfw control socket should not accept
-		 * unsupported rules), but better play safe and drop
-		 * packets in case of doubt.
-		 */
-		if ( (off & IP_FW_PORT_DENY_FLAG) || m == NULL) {
-			if (m)
-				m_freem(m);
-			error = EACCES;
+			error = netisr_queue(NETISR_IP, m);
 			goto done;
-		}
-		ip = mtod(m, struct ip *);
-		if (off == 0 && dst == old)		/* common case */
-			goto pass;
-                if (DUMMYNET_LOADED && (off & IP_FW_PORT_DYNT_FLAG) != 0) {
-			/*
-			 * pass the pkt to dummynet. Need to include
-			 * pipe number, m, ifp, ro, dst because these are
-			 * not recomputed in the next pass.
-			 * All other parameters have been already used and
-			 * so they are not needed anymore. 
-			 * XXX note: if the ifp or ro entry are deleted
-			 * while a pkt is in dummynet, we are in trouble!
-			 */ 
-			args.ro = ro;
-			args.dst = dst;
-			args.flags = flags;
+		} else
+			goto again;
+	}
 
-			error = ip_dn_io_ptr(m, off & 0xffff, DN_TO_IP_OUT,
-				&args);
-			goto done;
+#ifdef IPFIREWALL_FORWARD
+	/* See if local, if yes, send it to netisr with IP_FASTFWD_OURS. */
+	if (m->m_flags & M_FASTFWD_OURS) {
+		if (m->m_pkthdr.rcvif == NULL)
+			m->m_pkthdr.rcvif = ifunit("lo0");
+		if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
+			m->m_pkthdr.csum_flags |=
+			    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+			m->m_pkthdr.csum_data = 0xffff;
 		}
-#ifdef IPDIVERT
-		if (off != 0 && (off & IP_FW_PORT_DYNT_FLAG) == 0) {
-			struct mbuf *clone;
-
-			/* Clone packet if we're doing a 'tee' */
-			if ((off & IP_FW_PORT_TEE_FLAG) != 0)
-				clone = divert_clone(m);
-			else
-				clone = NULL;
+		m->m_pkthdr.csum_flags |=
+			    CSUM_IP_CHECKED | CSUM_IP_VALID;
 
-			/* 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;
-		}
+		error = netisr_queue(NETISR_IP, m);
+		goto done;
+	}
+	/* Or forward to some other address? */
+	fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+	if (fwd_tag) {
+		bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in));
+		m->m_flags |= M_SKIP_FIREWALL;
+		m_tag_delete(m, fwd_tag);
+		goto again;
+	}
 #endif
 
-		/* IPFIREWALL_FORWARD */
-		/*
-		 * Check dst to make sure it is directly reachable on the
-		 * interface we previously thought it was.
-		 * If it isn't (which may be likely in some situations) we have
-		 * to re-route it (ie, find a route for the next-hop and the
-		 * associated interface) and set them here. This is nested
-		 * forwarding which in most cases is undesirable, except where
-		 * such control is nigh impossible. So we do it here.
-		 * And I'm babbling.
-		 */
-		if (off == 0 && old != dst) { /* FORWARD, dst has changed */
-#if 0
-			/*
-			 * XXX To improve readability, this block should be
-			 * changed into a function call as below:
-			 */
-			error = ip_ipforward(&m, &dst, &ifp);
-			if (error)
-				goto bad;
-			if (m == NULL) /* ip_input consumed the mbuf */
-				goto done;
-#else
-			struct in_ifaddr *ia;
-
-			/*
-			 * XXX sro_fwd below is static, and a pointer
-			 * to it gets passed to routines downstream.
-			 * This could have surprisingly bad results in
-			 * practice, because its content is overwritten
-			 * by subsequent packets.
-			 * XXX: Breaks on SMP and possibly preemption!
-			 */
-			/* There must be a better way to do this next line... */
-			static struct route sro_fwd;
-			struct route *ro_fwd = &sro_fwd;
+#endif /* PFIL_HOOKS */
 
 #if 0
-			print_ip("IPFIREWALL_FORWARD: New dst ip: ",
-			    dst->sin_addr, "\n");
-#endif
-
-			/*
-			 * We need to figure out if we have been forwarded
-			 * to a local socket. If so, then we should somehow 
-			 * "loop back" to ip_input, and get directed to the
-			 * PCB as if we had received this packet. This is
-			 * because it may be dificult to identify the packets
-			 * you want to forward until they are being output
-			 * and have selected an interface. (e.g. locally
-			 * initiated packets) If we used the loopback inteface,
-			 * we would not be able to control what happens 
-			 * as the packet runs through ip_input() as
-			 * it is done through an ISR.
-			 */
-			LIST_FOREACH(ia,
-			    INADDR_HASH(dst->sin_addr.s_addr), ia_hash) {
-				/*
-				 * If the addr to forward to is one
-				 * of ours, we pretend to
-				 * be the destination for this packet.
-				 */
-				if (IA_SIN(ia)->sin_addr.s_addr ==
-						 dst->sin_addr.s_addr)
-					break;
-			}
-			if (ia) {	/* tell ip_input "dont filter" */
-				mtag = m_tag_get(
-				    PACKET_TAG_IPFORWARD,
-				    sizeof(struct sockaddr_in *), M_NOWAIT);
-				if (mtag == NULL) {
-					error = ENOBUFS;
-					goto bad;
-				}
-				*(struct sockaddr_in **)(mtag+1) =
-				    args.next_hop;
-				m_tag_prepend(m, mtag);
-
-				if (m->m_pkthdr.rcvif == NULL)
-					m->m_pkthdr.rcvif = ifunit("lo0");
-				if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
-					m->m_pkthdr.csum_flags |=
-					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
-					m->m_pkthdr.csum_data = 0xffff;
-				}
-				m->m_pkthdr.csum_flags |=
-				    CSUM_IP_CHECKED | CSUM_IP_VALID;
-				ip->ip_len = htons(ip->ip_len);
-				ip->ip_off = htons(ip->ip_off);
-				ip_input(m);
-				goto done;
-			}
-			/*
-			 * Some of the logic for this was
-			 * nicked from above.
-			 */
-			bcopy(dst, &ro_fwd->ro_dst, sizeof(*dst));
-
-			ro_fwd->ro_rt = 0;
-			rtalloc_ign(ro_fwd, RTF_CLONING);
-
-			if (ro_fwd->ro_rt == NULL) {
-				ipstat.ips_noroute++;
-				error = EHOSTUNREACH;
-				goto bad;
-			}
-
-			ia = ifatoia(ro_fwd->ro_rt->rt_ifa);
-			ifp = ro_fwd->ro_rt->rt_ifp;
-			ro_fwd->ro_rt->rt_rmx.rmx_pksent++;
-			if (ro_fwd->ro_rt->rt_flags & RTF_GATEWAY)
-				dst = (struct sockaddr_in *)
-					ro_fwd->ro_rt->rt_gateway;
-			if (ro_fwd->ro_rt->rt_flags & RTF_HOST)
-				isbroadcast =
-				    (ro_fwd->ro_rt->rt_flags & RTF_BROADCAST);
-			else
-				isbroadcast = in_broadcast(dst->sin_addr, ifp);
-			if (ro->ro_rt)
-				RTFREE(ro->ro_rt);
-			ro->ro_rt = ro_fwd->ro_rt;
-			dst = (struct sockaddr_in *)&ro_fwd->ro_dst;
-
-#endif	/* ... block to be put into a function */
-			/*
-			 * If we added a default src ip earlier,
-			 * which would have been gotten from the-then
-			 * interface, do it again, from the new one.
-			 */
-			if (src_was_INADDR_ANY)
-				ip->ip_src = IA_SIN(ia)->sin_addr;
-			goto pass ;
-		}
-
-                /*
-                 * if we get here, none of the above matches, and 
-                 * we have to drop the pkt
-                 */
-		m_freem(m);
-                error = EACCES; /* not sure this is the right error msg */
-                goto done;
-	}
-
 pass:
+#endif
 	/* 127/8 must not appear on wire - RFC1122. */
 	if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
 	    (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
@@ -1042,13 +814,6 @@ pass:
 done:
 	if (ro == &iproute && ro->ro_rt) {
 		RTFREE(ro->ro_rt);
-		ro->ro_rt = NULL;
-	}
-	if (dummytag) {
-		struct dn_pkt_tag *dt = (struct dn_pkt_tag *)(dummytag+1);
-		if (dt->ro.ro_rt)
-			RTFREE(dt->ro.ro_rt);
-		m_tag_free(dummytag);
 	}
 #ifdef IPSEC
 	if (sp != NULL) {
@@ -1263,108 +1028,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 == NULL) {
-			*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
@@ -1648,108 +1311,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 - (IPOPT_MINOFF - 1));
-			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	13 Aug 2004 21:18:06 -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);
 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.139
diff -u -p -r1.139 raw_ip.c
--- netinet/raw_ip.c	11 Aug 2004 20:30:08 -0000	1.139
+++ netinet/raw_ip.c	13 Aug 2004 21:18:06 -0000
@@ -79,8 +79,8 @@ struct	inpcbhead ripcb;
 struct	inpcbinfo ripcbinfo;
 
 /* control hooks for ipfw and dummynet */
-ip_fw_ctl_t *ip_fw_ctl_ptr;
-ip_dn_ctl_t *ip_dn_ctl_ptr;
+ip_fw_ctl_t *ip_fw_ctl_ptr = NULL;
+ip_dn_ctl_t *ip_dn_ctl_ptr = NULL;
 
 /*
  * hooks for multicast routing. They all default to NULL,
@@ -363,14 +363,14 @@ rip_ctloutput(struct socket *so, struct 
 		case IP_FW_GET:
 		case IP_FW_TABLE_GETSIZE:
 		case IP_FW_TABLE_LIST:
-			if (IPFW_LOADED)
+			if (ip_fw_ctl_ptr != NULL)
 				error = ip_fw_ctl_ptr(sopt);
 			else
 				error = ENOPROTOOPT;
 			break;
 
 		case IP_DUMMYNET_GET:
-			if (DUMMYNET_LOADED)
+			if (ip_dn_ctl_ptr != NULL)
 				error = ip_dn_ctl_ptr(sopt);
 			else
 				error = ENOPROTOOPT;
@@ -419,7 +419,7 @@ rip_ctloutput(struct socket *so, struct 
 		case IP_FW_TABLE_ADD:
 		case IP_FW_TABLE_DEL:
 		case IP_FW_TABLE_FLUSH:
-			if (IPFW_LOADED)
+			if (ip_fw_ctl_ptr != NULL)
 				error = ip_fw_ctl_ptr(sopt);
 			else
 				error = ENOPROTOOPT;
@@ -428,7 +428,7 @@ rip_ctloutput(struct socket *so, struct 
 		case IP_DUMMYNET_CONFIGURE:
 		case IP_DUMMYNET_DEL:
 		case IP_DUMMYNET_FLUSH:
-			if (DUMMYNET_LOADED)
+			if (ip_dn_ctl_ptr != NULL)
 				error = ip_dn_ctl_ptr(sopt);
 			else
 				error = ENOPROTOOPT ;
Index: netinet/tcp_input.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/tcp_input.c,v
retrieving revision 1.250
diff -u -p -r1.250 tcp_input.c
--- netinet/tcp_input.c	12 Jul 2004 19:28:07 -0000	1.250
+++ netinet/tcp_input.c	13 Aug 2004 21:18:07 -0000
@@ -68,6 +68,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>
@@ -429,7 +430,9 @@ tcp_input(m, off0)
 	struct tcpopt to;		/* options in this segment */
 	struct rmxp_tao tao;		/* our TAO cache entry */
 	int headlocked = 0;
-	struct sockaddr_in *next_hop = NULL;
+#ifdef IPFIREWALL_FORWARD
+	struct m_tag *fwd_tag;
+#endif
 	int rstreason; /* For badport_bandlim accounting purposes */
 
 	struct ip6_hdr *ip6 = NULL;
@@ -449,8 +452,6 @@ tcp_input(m, off0)
 	short ostate = 0;
 #endif
 
-	/* Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. */
-	next_hop = m_claim_next(m, PACKET_TAG_IPFORWARD);
 #ifdef INET6
 	isipv6 = (mtod(m, struct ip *)->ip_v == 6) ? 1 : 0;
 #endif
@@ -611,13 +612,20 @@ tcp_input(m, off0)
 	INP_INFO_WLOCK(&tcbinfo);
 	headlocked = 1;
 findpcb:
-	/* IPFIREWALL_FORWARD section */
-	if (next_hop != NULL && isipv6 == 0) {	/* IPv6 support is not yet */
+#ifdef IPFIREWALL_FORWARD
+        /* Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. */
+        fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+
+	if (fwd_tag != NULL && isipv6 == 0) {	/* IPv6 support is not yet */
+		struct sockaddr_in *next_hop;
+
+		next_hop = (sockaddr_in *)(fwd_tag+1);
 		/*
 		 * Transparently forwarded. Pretend to be the destination.
 		 * already got one like this? 
 		 */
-		inp = in_pcblookup_hash(&tcbinfo, ip->ip_src, th->th_sport,
+		inp = in_pcblookup_hash(&tcbinfo,
+					ip->ip_src, th->th_sport,
 					ip->ip_dst, th->th_dport,
 					0, m->m_pkthdr.rcvif);
 		if (!inp) {
@@ -630,7 +638,10 @@ findpcb:
 						    th->th_dport,
 						1, m->m_pkthdr.rcvif);
 		}
+		/* Remove the tag from the packet.  We don't need it anymore. */
+		m_tag_delete(m, next_hop);
 	} else {
+#endif /* IPFIREWALL_FORWARD */
 		if (isipv6) {
 #ifdef INET6
 			inp = in6_pcblookup_hash(&tcbinfo,
@@ -643,7 +654,9 @@ findpcb:
 						ip->ip_src, th->th_sport,
 						ip->ip_dst, th->th_dport,
 						1, m->m_pkthdr.rcvif);
+#ifdef IPFIREWALL_FORWARD
       }
+#endif /* IPFIREWALL_FORWARD */
 
 #if defined(IPSEC) || defined(FAST_IPSEC)
 #ifdef INET6
Index: netinet/tcp_output.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/tcp_output.c,v
retrieving revision 1.99
diff -u -p -r1.99 tcp_output.c
--- netinet/tcp_output.c	28 Jul 2004 02:15:14 -0000	1.99
+++ netinet/tcp_output.c	13 Aug 2004 21:18:07 -0000
@@ -57,6 +57,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.64
diff -u -p -r1.64 tcp_syncache.c
--- netinet/tcp_syncache.c	11 Aug 2004 20:30:08 -0000	1.64
+++ netinet/tcp_syncache.c	13 Aug 2004 21:18:07 -0000
@@ -64,6 +64,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>
@@ -650,7 +651,7 @@ syncache_socket(sc, lso, m)
 		struct in_addr laddr;
 		struct sockaddr_in sin;
 
-		inp->inp_options = ip_srcroute();
+		inp->inp_options = ip_srcroute(m);
 		if (inp->inp_options == NULL) {
 			inp->inp_options = sc->sc_ipopts;
 			sc->sc_ipopts = NULL;
@@ -848,7 +849,7 @@ syncache_add(inc, to, th, sop, m)
 #ifdef INET6
 	if (!inc->inc_isipv6)
 #endif
-		ipopts = ip_srcroute();
+		ipopts = ip_srcroute(m);
 
 	/*
 	 * See if we already have an entry for this connection.
Index: netinet/udp_usrreq.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/udp_usrreq.c,v
retrieving revision 1.161
diff -u -p -r1.161 udp_usrreq.c
--- netinet/udp_usrreq.c	12 Aug 2004 01:34:27 -0000	1.161
+++ netinet/udp_usrreq.c	13 Aug 2004 21:18:07 -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
Index: sys/mbuf.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/mbuf.h,v
retrieving revision 1.156
diff -u -p -r1.156 mbuf.h
--- sys/mbuf.h	2 Aug 2004 00:18:35 -0000	1.156
+++ sys/mbuf.h	13 Aug 2004 21:18:07 -0000
@@ -642,6 +642,7 @@ struct	mbuf	*m_uiotombuf(struct uio *, i
 #define	PACKET_TAG_PF_TAG			24 /* PF tagged */
 #define	PACKET_TAG_RTSOCKFAM			25 /* rtsock sa family */
 #define	PACKET_TAG_PF_TRANSLATE_LOCALHOST	26 /* PF translate localhost */
+#define	PACKET_TAG_IPOPTIONS			27 /* Saved IP options */
 
 /* Packet tag routines. */
 struct	m_tag	*m_tag_alloc(u_int32_t, int, int, int);
@@ -737,21 +738,6 @@ m_tag_find(struct mbuf *m, int type, str
 	    NULL : m_tag_locate(m, MTAG_ABI_COMPAT, type, start));
 }
 
-/*
- * Obtain next_hop information associated with the mbuf, if any.
- * If a tag is present devalidate it also.
- */
-static __inline struct sockaddr_in *
-m_claim_next(struct mbuf *m, int type)
-{
-	struct m_tag *mtag = m_tag_find(m, type, NULL);
-	if (mtag) {
-		struct sockaddr_in *sin = *(struct sockaddr_in **)(mtag + 1);
-		mtag->m_tag_id = PACKET_TAG_NONE;
-		return (sin);
-	}
-	return (NULL);
-}
 #endif /* _KERNEL */
 
 #endif /* !_SYS_MBUF_H_ */
Index: sys/socket.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/socket.h,v
retrieving revision 1.83
diff -u -p -r1.83 socket.h
--- sys/socket.h	11 Aug 2004 10:18:49 -0000	1.83
+++ sys/socket.h	13 Aug 2004 21:18:07 -0000
@@ -206,6 +206,7 @@ struct accept_filter_arg {
 #define	AF_ARP		35
 #define	AF_BLUETOOTH	36		/* Bluetooth sockets */
 #define	AF_MAX		37
+#define	AF_ETHER	38		/* Ethernet frames */
 #endif
 
 /*
--- netinet/null	Mon May 10 22:17:30 2004
+++ netinet/ip_fw_pfil.c	Fri Aug 13 23:00:48 2004
@@ -0,0 +1,369 @@
+/*
+ * 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>
+
+#include <machine/in_cksum.h>
+
+static	int ipfw_pfil_hooked = 0;
+
+/* Dummynet hooks */
+ip_dn_io_t	*ip_dn_io_ptr = NULL;
+ip_dn_ruledel_t	*ip_dn_ruledel_ptr = NULL;
+
+#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;
+	struct m_tag *dn_tag;
+	int ipfw = 0;
+	int divert;
+#ifdef IPFIREWALL_FORWARD
+	struct m_tag *fwd_tag;
+#endif
+
+	KASSERT(dir == PFIL_IN, ("ipfw_check_in wrong direction!"));
+
+	bzero(&args, sizeof(args));
+
+	dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
+	if (dn_tag != NULL){
+		struct dn_pkt_tag *dt;
+
+		dt = (struct dn_pkt_tag *)(dn_tag+1);
+		args.rule = dt->rule;
+
+		m_tag_delete(*m0, dn_tag);
+	}
+
+	args.m = *m0;
+	ipfw = ipfw_chk(&args);
+	*m0 = args.m;
+
+	if ((ipfw & IP_FW_PORT_DENY_FLAG) || *m0 == NULL)
+		goto drop;
+
+	if (ipfw == 0 && args.next_hop == NULL)
+		goto pass;
+
+	if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
+		ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_IN, &args);
+		*m0 = NULL;
+		return 0;		/* packet consumed */
+	}
+
+	if (ipfw != 0 && (ipfw & IP_FW_PORT_DYNT_FLAG) == 0) {
+		if ((ipfw & IP_FW_PORT_TEE_FLAG) != 0)
+			divert = ipfw_divert(m0, DIV_DIR_IN, 1);
+		else
+			divert = ipfw_divert(m0, DIV_DIR_IN, 0);
+
+		/* tee should continue again with the firewall. */
+		if (divert) {
+			*m0 = NULL;
+			return 0;	/* packet consumed */
+		} else
+			goto pass;	/* continue with packet */
+	}
+
+#ifdef IPFIREWALL_FORWARD
+	if (ipfw == 0 && args.next_hop != NULL) {
+		fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
+				sizeof(struct sockaddr_in), M_NOWAIT);
+		if (fwd_tag == NULL)
+			goto drop;
+
+		bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
+		m_tag_prepend(*m0, fwd_tag);
+
+		if (in_localip(args.next_hop->sin_addr))
+			(*m0)->m_flags |= M_FASTFWD_OURS;
+	}
+#endif
+
+drop:
+	if (*m0)
+		m_freem(*m0);
+	*m0 = NULL;
+	return (EACCES);
+pass:
+	return 0;	/* not filtered */
+}
+
+int
+ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
+{
+	struct ip_fw_args args;
+	struct m_tag *dn_tag;
+	int ipfw = 0;
+	int divert;
+#ifdef IPFIREWALL_FORWARD
+	struct m_tag *fwd_tag;
+#endif
+
+	KASSERT(dir == PFIL_OUT, ("ipfw_check_out wrong direction!"));
+
+	bzero(&args, sizeof(args));
+
+	dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
+	if (dn_tag != NULL){
+		struct dn_pkt_tag *dt;
+
+		dt = (struct dn_pkt_tag *)(dn_tag+1);
+		args.rule = dt->rule;
+
+		m_tag_delete(*m0, dn_tag);
+	}
+
+	args.m = *m0;
+	args.oif = ifp;
+	ipfw = ipfw_chk(&args);
+	*m0 = args.m;
+
+	if ((ipfw & IP_FW_PORT_DENY_FLAG) || *m0 == NULL)
+		goto drop;
+
+	if (ipfw == 0 && args.next_hop == NULL)
+		goto pass;
+
+	if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
+		ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_OUT, &args);
+		*m0 = NULL;
+		return 0;		/* packet consumed */
+	}
+
+	if (ipfw != 0 && (ipfw & IP_FW_PORT_DYNT_FLAG) == 0) {
+		if ((ipfw & IP_FW_PORT_TEE_FLAG) != 0)
+			divert = ipfw_divert(m0, DIV_DIR_OUT, 1);
+		else
+			divert = ipfw_divert(m0, DIV_DIR_OUT, 0);
+
+		if (divert) {
+			*m0 = NULL;
+			return 0;	/* packet consumed */
+		} else
+			goto pass;	/* continue with packet */
+        }
+
+#ifdef IPFIREWALL_FORWARD
+	if (ipfw == 0 && args.next_hop != NULL) {
+		fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
+				sizeof(struct sockaddr_in), M_NOWAIT);
+		if (fwd_tag == NULL)
+			goto drop;
+
+		bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
+		m_tag_prepend(*m0, fwd_tag);
+
+		if (in_localip(args.next_hop->sin_addr))
+			(*m0)->m_flags |= M_FASTFWD_OURS;
+	}
+#endif
+
+drop:
+	if (*m0)
+		m_freem(*m0);
+	*m0 = NULL;
+	return (EACCES);
+pass:
+	return 0;	/* not filtered */
+}
+
+#define	IPDIVERT	1	/* XXX */
+
+static int
+ipfw_divert(struct mbuf **m, int incoming, int tee)
+{
+	/*
+	 * ipfw_chk() has already tagged the packet with the divert
+	 * tag.  For tee we need to remove the tag.
+	 * If tee is set, copy packet and return original.
+	 * If not tee, consume packet and send it to divert socket.
+	 */
+#ifdef IPDIVERT
+	struct mbuf *clone, *reass;
+	struct m_tag *mtag;
+	struct ip *ip;
+	int hlen;
+
+	reass = NULL;
+
+	/* Cloning needed for tee? */
+	if (tee)
+		clone = m_dup(*m, M_DONTWAIT);
+	else
+		clone = *m;
+
+	/* In case m_dup was unable to allocate mbufs. */
+	if (clone == NULL)
+		goto teeout;
+
+	/*
+	 * Divert listeners can only handle non-fragmented packets.
+	 * However when tee is set we will *not* de-fragment the packets;
+	 * Doing do would put the reassembly into double-jeopardy.  On top
+	 * of that someone doing a tee will probably want to get the packet
+	 * in its original form.
+	 */
+	ip = mtod(clone, struct ip *);
+	if (!tee && ip->ip_off & (IP_MF | IP_OFFMASK)) {
+
+		/* Reassemble packet. */
+		reass = ip_reass(clone);
+
+		/*
+		 * IP header checksum fixup after reassembly and leave header
+		 * in network byte order.
+		 */
+		if (reass != NULL) {
+			ip = mtod(reass, struct ip *);
+			hlen = ip->ip_hl << 2;
+			ip->ip_len = htons(ip->ip_len);
+			ip->ip_off = htons(ip->ip_off);
+			ip->ip_sum = 0;
+			if (hlen == sizeof(struct ip))
+				ip->ip_sum = in_cksum_hdr(ip);
+			else
+				ip->ip_sum = in_cksum(reass, hlen);
+			clone = reass;
+		} else
+			clone = NULL;
+	} else {
+		/* Convert header to network byte order. */
+		ip->ip_len = htons(ip->ip_len);
+		ip->ip_off = htons(ip->ip_off);
+	}
+
+	/* Do the dirty job... */
+	if (clone)
+		divert_packet(clone, incoming);
+
+teeout:
+	if (tee) {
+		mtag = m_tag_find(*m, PACKET_TAG_DIVERT, NULL);
+		if (mtag != NULL)
+			m_tag_delete(*m, mtag);
+		return 0;	/* continue with original packet. */
+	}
+
+	/* Packet diverted and consumed */
+	return 1;
+#else
+	m_freem(*m);
+	return 1;
+#endif	/* ipdivert */
+}
+
+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.c	Fri Aug 13 21:23:06 2004
@@ -0,0 +1,720 @@
+/*
+ * 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(struct mbuf *m, u_char *, struct in_addr);
+
+
+/*
+ * 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 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(m, 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);
+		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(m, option, dst)
+	struct mbuf *m;
+	u_char *option;
+	struct in_addr dst;
+{
+	unsigned olen;
+	struct ipopt_tag *opts;
+
+	opts = (struct ipopt_tag *)m_tag_get(PACKET_TAG_IPOPTIONS,
+					sizeof(struct ipopt_tag), M_NOWAIT);
+	if (opts == NULL)
+		return;
+
+	olen = option[IPOPT_OLEN];
+#ifdef DIAGNOSTIC
+	if (ipprintfs)
+		printf("save_rte: olen %d\n", olen);
+#endif
+	if (olen > sizeof(opts->ip_srcrt) - (1 + sizeof(dst)))
+		return;
+	bcopy(option, opts->ip_srcrt.srcopt, olen);
+	opts->ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
+	opts->ip_srcrt.dst = dst;
+	m_tag_prepend(m, (struct m_tag *)opts);
+}
+
+/*
+ * 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(m0)
+	struct mbuf *m0;
+{
+	register struct in_addr *p, *q;
+	register struct mbuf *m;
+	struct ipopt_tag *opts;
+
+	opts = (struct ipopt_tag *)m_tag_find(m0, PACKET_TAG_IPOPTIONS, NULL);
+	if (opts == NULL)
+		return ((struct mbuf *)0);
+
+	if (opts->ip_nhops == 0)
+		return ((struct mbuf *)0);
+	m = m_get(M_DONTWAIT, MT_HEADER);
+	if (m == 0)
+		return ((struct mbuf *)0);
+
+#define OPTSIZ	(sizeof(opts->ip_srcrt.nop) + sizeof(opts->ip_srcrt.srcopt))
+
+	/* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
+	m->m_len = opts->ip_nhops * sizeof(struct in_addr) +
+	    sizeof(struct in_addr) + OPTSIZ;
+#ifdef DIAGNOSTIC
+	if (ipprintfs)
+		printf("ip_srcroute: nhops %d mlen %d", opts->ip_nhops, m->m_len);
+#endif
+
+	/*
+	 * First save first hop for return route
+	 */
+	p = &(opts->ip_srcrt.route[opts->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.
+	 */
+	opts->ip_srcrt.nop = IPOPT_NOP;
+	opts->ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
+	(void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr),
+	    &(opts->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 >= opts->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 = opts->ip_srcrt.dst;
+#ifdef DIAGNOSTIC
+	if (ipprintfs)
+		printf(" %lx\n", (u_long)ntohl(q->s_addr));
+#endif
+	m_tag_delete(m0, (struct m_tag *)opts);
+	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 - (IPOPT_MINOFF - 1));
+			break;
+		}
+	}
+	if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
+		goto bad;
+	*pcbopt = m;
+	return (0);
+
+bad:
+	(void)m_free(m);
+	return (EINVAL);
+}
--- netinet/null	Mon May 10 22:17:30 2004
+++ netinet/ip_options.h	Fri Aug 13 21:16:04 2004
@@ -0,0 +1,74 @@
+/*
+ * 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 ipoptrt {
+        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)];
+};
+
+struct ipopt_tag {
+	struct	m_tag tag;			/* m_tag */
+	int	ip_nhops;
+	struct	ipoptrt ip_srcrt;
+};
+
+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 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(struct mbuf *);
+
+#endif /* !_NETINET_IP_OPTIONS_H_ */
