Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 24 Mar 2004 11:53:53 +0100
From:      "Mariano" <tortomari@email.it>
To:        "freebsd-ipfw" <freebsd-ipfw@freebsd.org>
Cc:        freebsd-net <freebsd-net@freebsd.org>
Subject:   Request for testing ipfw2/dummynet under ipv6
Message-ID:  <HV2U9T$474E23C8CE7B556828F1BE7687979F9C@email.it>

index | next in thread | raw e-mail

[-- Attachment #1 --]
Hi,
I've develped with my friend Raffaele De Lorenzo a working version of ipfw2/dummynet with the support of IPv6 protocol, this is an upgrade 

of the previous version posted on
http://docs.freebsd.org/cgi/getmsg.cgi?fetch=44395+0+archive/2004/freebsd-ipfw/20040118.freebsd-ipfw by my supervisor Luigi Rizzo in
14 Jan.

THIS IS STILL AN EVALUATION CODE, DO NOT USE AS REGULAR

We have solved the bugs of the previous code and this seems to work, the semantic of the userland interface is still under development. The
"-h" opt will explain the actual status.

Could someone help us in the testing fase? We wait any suggestion and help. 

Thanks,
Mariano e Raffaele


--
Email.it, the professional e-mail, gratis per te: http://www.email.it/f

Sponsor:
Una torcia . Niente batterie. Per caricarla basta AGITARE!!!

Clicca qui: http://adv.email.it/cgi-bin/foclick.cgi?mid=2411&d=24-3
[-- Attachment #2 --]
--- ./originali/ip6_forward.c	Wed Jan 14 10:43:54 2004
+++ ./sys/netinet6/ip6_forward.c	Tue Mar 23 15:15:52 2004
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  */
 
-#include "opt_ip6fw.h"
+#include "opt_ipfw.h"
 #include "opt_inet.h"
 #include "opt_inet6.h"
 #include "opt_ipsec.h"
@@ -454,6 +454,8 @@
 		type = ND_REDIRECT;
 	}
 
+#ifdef IPFW2	/* XXX this needs to be filled up */
+#else /* !IPFW2 */
 	/*
 	 * Check with the firewall...
 	 */
@@ -467,7 +469,7 @@
 		if (!m)
 			goto freecopy;
 	}
-
+#endif
 	/*
 	 * Fake scoped addresses. Note that even link-local source or
 	 * destinaion can appear, if the originating node just sends the
--- ./originali/ip6_input.c	Wed Jan 14 10:35:41 2004
+++ ./sys/netinet6/ip6_input.c	Tue Mar 23 15:15:53 2004
@@ -65,7 +65,7 @@
  *	@(#)ip_input.c	8.2 (Berkeley) 1/4/94
  */
 
-#include "opt_ip6fw.h"
+#include "opt_ipfw.h"
 #include "opt_inet.h"
 #include "opt_inet6.h"
 #include "opt_ipsec.h"
@@ -119,7 +119,12 @@
 #define	IPSEC
 #endif /* FAST_IPSEC */
 
+#ifdef IPFW2
+#include <netinet/ip_fw.h>
+#include <netinet/ip_dummynet.h>
+#else
 #include <netinet6/ip6_fw.h>
+#endif
 
 #include <netinet6/ip6protosw.h>
 
@@ -148,9 +153,11 @@
 
 
 /* firewall hooks */
+#ifndef IPFW2
 ip6_fw_chk_t *ip6_fw_chk_ptr;
 ip6_fw_ctl_t *ip6_fw_ctl_ptr;
 int ip6_fw_enable = 1;
+#endif	/* !IPFW2 */
 
 struct ip6stat ip6stat;
 
@@ -263,6 +270,53 @@
 	int nxt, ours = 0;
 	struct ifnet *deliverifp = NULL;
 
+#ifdef IPFW2
+	int    i, hlen;
+#ifdef	IPDIVERT
+	u_int32_t divert_info = 0;              /* packet divert/tee info */
+#endif
+	struct ip_fw_args args;
+	args.eh = NULL;
+	args.oif = NULL;
+	args.rule = NULL;
+	args.divert_rule = 0;                   /* divert cookie */
+	args.next_hop = NULL;
+
+	/* Grab info from MT_TAG mbufs prepended to the chain.  */
+	for (; m && m->m_type == MT_TAG; m = m->m_next) {
+		switch(m->_m_tag_id) {
+		default:
+			printf("ip6_input: unrecognised MT_TAG tag %d\n",
+				m->_m_tag_id);
+			break;
+
+		case PACKET_TAG_DUMMYNET:
+			args.rule = ((struct dn_pkt *)m)->rule;
+			break;
+
+		case PACKET_TAG_DIVERT:
+			args.divert_rule = (int)m->m_hdr.mh_data & 0xffff;
+			break;
+
+#if 0
+		/* The ipfw2 forwarding is not yet implemented in ipv6  */
+		case PACKET_TAG_IPFORWARD:
+			args.next_hop = (struct sockaddr_in *)m->m_hdr.mh_data;
+			break;
+#endif
+		}
+	}
+
+	KASSERT(m != NULL && (m->m_flags & M_PKTHDR) != 0,
+			("ip6_input: no HDR"));
+
+	if (args.rule) {        /* dummynet already filtered us */
+		ip6 = mtod(m, struct ip6_hdr *);
+		hlen = sizeof (struct ip6_hdr);
+		goto iphack;
+	}
+#endif /* IPFW2 */
+
 #ifdef IPSEC
 	/*
 	 * should the inner packet be considered authentic?
@@ -354,6 +408,7 @@
 		goto bad;
 	}
 
+iphack:
 	/*
 	 * Check if we want to allow this packet to be processed.
 	 * Consider it to be bad if not.
@@ -375,6 +430,50 @@
 	/*
 	 * Check with the firewall...
 	 */
+#ifdef IPFW2
+	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)
+			ours=1; /* XXX check if this is correct */
+
+		args.m = m;
+		i = ip_fw_chk_ptr(&args);
+		m = args.m;
+
+		if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */
+			if (m)
+				m_freem(m);
+			return;
+		}
+		ip6 = mtod(m, struct ip6_hdr *); /* 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_IP6_IN, &args);
+			return;
+		}
+#ifdef IPDIVERT
+		if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) {
+			/* Divert or tee packet */
+			divert_info = i;
+			ours=1;
+		}
+#endif
+		if (i == 0 && args.next_hop != NULL)
+			goto pass;
+		/*
+		 * if we get here, the packet must be dropped
+		 */
+		m_freem(m);
+		return;
+	}
+pass:
+#else	/* !IPFW2, use the old firewall */
 	if (ip6_fw_enable && ip6_fw_chk_ptr) {
 		u_short port = 0;
 		/* If ipfw says divert, we have to just drop packet */
@@ -386,6 +485,7 @@
 		if (!m)
 			return;
 	}
+#endif	/* !IPFW2 */
 
 	/*
 	 * Check against address spoofing/corruption.
--- ./originali/ip6_output.c	Wed Jan 14 10:35:41 2004
+++ ./sys/netinet6/ip6_output.c	Tue Mar 23 15:15:52 2004
@@ -65,7 +65,7 @@
  *	@(#)ip_output.c	8.3 (Berkeley) 1/21/94
  */
 
-#include "opt_ip6fw.h"
+#include "opt_ipfw.h"
 #include "opt_inet.h"
 #include "opt_inet6.h"
 #include "opt_ipsec.h"
@@ -107,7 +107,13 @@
 #include <netipsec/key.h>
 #endif /* FAST_IPSEC */
 
+#ifdef IPFW2
+#include <netinet/ip_var.h>
+#include <netinet/ip_fw.h>
+#include <netinet/ip_dummynet.h>
+#else  /* use old ip6fw */
 #include <netinet6/ip6_fw.h>
+#endif
 
 #include <net/net_osdep.h>
 
@@ -169,6 +175,9 @@
 	struct route_in6 *ro_pmtu = NULL;
 	int hdrsplit = 0;
 	int needipsec = 0;
+#ifdef	IPFW2
+	struct ip_fw_args args;
+#endif
 #ifdef IPSEC
 	int needipsectun = 0;
 	struct secpolicy *sp = NULL;
@@ -183,6 +192,66 @@
 	ip6 = mtod(m, struct ip6_hdr *);
 #endif /* FAST_IPSEC */
 
+#ifdef IPFW2
+	args.eh = NULL;
+	args.rule = NULL;
+	args.next_hop = NULL;
+	args.divert_rule = 0;                   /* divert cookie */
+
+	/* Grab info from MT_TAG mbufs prepended to the chain. */
+	for (; m0 && m0->m_type == MT_TAG; m0 = m0->m_next) {
+		switch(m0->_m_tag_id) {
+		default:
+			printf("ip6_output: unrecognised MT_TAG tag %d\n",
+				m0->_m_tag_id);
+			break;
+
+		case PACKET_TAG_DUMMYNET:
+			/*
+			 * the packet was already tagged, so part of the
+			 * processing was already done, and we need to go down.
+			 * Get parameters from the header.
+			 */
+			opt = NULL;
+			ro = &((struct dn_pkt *)m0)->ip6opt.ro_or;
+			flags = ((struct dn_pkt *)m0)->ip6opt.flags_or;
+                        im6o = NULL;
+			origifp = ((struct dn_pkt *)m0)->ip6opt.origifp_or;
+			ifp = ((struct dn_pkt *)m0)->ip6opt.ifp_or; 
+			dst =  &((struct dn_pkt *)m0)->ip6opt.dst_or;
+			args.rule=((struct dn_pkt *)m0)->rule;
+			break;
+
+		case PACKET_TAG_DIVERT:
+			args.divert_rule = (int)m0->m_data & 0xffff;
+			break;
+
+#if 0
+		/* ipfw2 Forwarding is not yet supported in ipv6 */
+		case PACKET_TAG_IPFORWARD:
+			args.next_hop = (struct sockaddr_in *)m0->m_data;
+			break;
+#endif
+		}
+	}
+	m = m0; 
+
+	KASSERT(!m || (m->m_flags & M_PKTHDR) != 0, ("ip6_output: no HDR"));
+#ifndef FAST_IPSEC
+	KASSERT(ro != NULL, ("ip6_output: no route\n"));
+#endif
+
+	if (args.rule ) {        /* dummynet already saw us */
+		ip6 = mtod(m, struct ip6_hdr *);
+		hlen = sizeof (struct ip6_hdr) ;
+		if (ro->ro_rt)
+			ia = ifatoia6(ro->ro_rt->rt_ifa);
+	        bzero(&exthdrs, sizeof(exthdrs));
+		ro_pmtu = ro;
+		goto send_after_dummynet;
+	}
+#endif	/* IPFW2 */
+
 #define MAKE_EXTHDR(hp, mp)						\
     do {								\
 	if (hp) {							\
@@ -455,7 +524,6 @@
 skip_ipsec2:;
 #endif
 	}
-
 	/*
 	 * If there is a routing header, replace destination address field
 	 * with the first hop of the routing header.
@@ -581,7 +649,6 @@
 		exthdrs.ip6e_ip6 = m;
 	}
 #endif /* IPSEC */
-
 	if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
 		/* Unicast */
 
@@ -760,7 +827,6 @@
 			goto done;
 		}
 	}
-
 	/*
 	 * Fill the outgoing inteface to tell the upper layer
 	 * to increment per-interface statistics.
@@ -768,6 +834,7 @@
 	if (ifpp)
 		*ifpp = ifp;
 
+send_after_dummynet:
 	/*
 	 * Determine path MTU.
 	 */
@@ -866,10 +933,71 @@
 	in6_clearscope(&ip6->ip6_src);
 	in6_clearscope(&ip6->ip6_dst);
 #endif
-
 	/*
 	 * Check with the firewall...
 	 */
+#ifdef IPFW2
+	if (fw_enable && IPFW_LOADED && !args.next_hop) {
+		/* 
+		 * Check with the firewall IPFW2...
+		 * but not if we are already being fwd'd from a firewall.
+		 */
+
+		struct sockaddr_in6 *old = dst;
+		args.m = m;
+		args.next_hop = (struct sockaddr_in *) dst;
+		args.oif = ifp;
+		off = ip_fw_chk_ptr(&args);
+		m = args.m;
+		dst = (struct sockaddr_in6 *) args.next_hop;
+
+		/*
+		 * On return we must do the following:
+		 * m == NULL    -> drop the pkt (old interface, deprecated)
+		 * (off & IP_FW_PORT_DENY_FLAG) -> drop the pkt (new interface)
+		 * 1<=off<= 0xffff              -> DIVERT
+		 * (off & IP_FW_PORT_DYNT_FLAG) -> send to a DUMMYNET pipe
+		 * (off & IP_FW_PORT_TEE_FLAG)  -> TEE the packet
+		 * dst != old                   -> IPFIREWALL_FORWARD
+		 * off==0, dst==old             -> accept
+		 * If some of the above modules are not compiled in, then
+		 * we should't have to check the corresponding condition
+		 * (because the ipfw control socket should not accept
+		 * unsupported rules), but better play safe and drop
+		 * packets in case of doubt.
+		 */
+		if ( (off & IP_FW_PORT_DENY_FLAG) || m == NULL) {
+			if (m)
+				m_freem(m);
+			error = EACCES;
+			goto done;
+		}
+		ip6 = mtod(m, struct ip6_hdr *);   /* XXX check if necessary */
+		if (off == 0 && dst == old)             /* common case */
+			goto pass6;
+		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.dummypar.ro_or = *ro;
+			args.dummypar.flags_or = flags;
+			args.dummypar.ifp_or = ifp;
+			args.dummypar.origifp_or = origifp;
+			args.dummypar.dst_or = *dst;
+			args.flags = flags;
+			error = ip_dn_io_ptr(m, off & 0xffff, DN_TO_IP6_OUT,
+				&args);
+			goto done;
+		}
+	}
+pass6:
+#else	/* !IPFW2 */
 	if (ip6_fw_enable && ip6_fw_chk_ptr) {
 		u_short port = 0;
 		m->m_pkthdr.rcvif = NULL;	/* XXX */
@@ -883,7 +1011,7 @@
 			goto done;
 		}
 	}
-
+#endif	/* !IPFW2 */
 	/*
 	 * If the outgoing packet contains a hop-by-hop options header,
 	 * it must be examined and processed even by the source node.
@@ -1115,7 +1243,6 @@
 	if (sp != NULL)
 		KEY_FREESP(&sp);
 #endif /* FAST_IPSEC */
-
 	return(error);
 
 freehdrs:
@@ -1548,6 +1675,7 @@
 				break;
 #endif /* KAME IPSEC */
 
+#ifndef IPFW2
 			case IPV6_FW_ADD:
 			case IPV6_FW_DEL:
 			case IPV6_FW_FLUSH:
@@ -1568,7 +1696,7 @@
 				m = *mp;
 			    }
 				break;
-
+#endif /* !IPFW2 */
 			default:
 				error = ENOPROTOOPT;
 				break;
@@ -1708,6 +1836,7 @@
 			  }
 #endif /* KAME IPSEC */
 
+#ifndef IPFW2
 			case IPV6_FW_GET:
 			  {
 				struct mbuf *m;
@@ -1724,6 +1853,7 @@
 					m_freem(m);
 			  }
 				break;
+#endif /* !IPFW2 */
 
 			default:
 				error = ENOPROTOOPT;
@@ -2046,8 +2176,8 @@
 		/*
 		 * If the interface is specified, validate it.
 		 */
-		if (mreq->ipv6mr_interface < 0
-		 || if_index < mreq->ipv6mr_interface) {
+		if (mreq->ipv6mr_interface < 0 ||
+		    if_index < mreq->ipv6mr_interface) {
 			error = ENXIO;	/* XXX EINVAL? */
 			break;
 		}
@@ -2097,7 +2227,7 @@
 		 */
 		if (IN6_IS_ADDR_MC_LINKLOCAL(&mreq->ipv6mr_multiaddr)) {
 			mreq->ipv6mr_multiaddr.s6_addr16[1]
-				= htons(mreq->ipv6mr_interface);
+				= htons(ifp->if_index);
 		}
 		/*
 		 * See if the membership already exists.
--- ./originali/ip_dummynet.c	Wed Jan 14 10:35:41 2004
+++ ./sys/netinet/ip_dummynet.c	Tue Mar 23 15:15:53 2004
@@ -85,6 +85,9 @@
 #include <netinet/if_ether.h> /* for struct arpcom */
 #include <net/bridge.h>
 
+#include <netinet/ip6.h>	/* for ip6_input, ip6_output prototypes */
+#include <netinet6/ip6_var.h>
+
 /*
  * We keep a private variable for the simulation time, but we could
  * probably use an existing one ("softticks" in sys/kern/kern_timer.c)
@@ -435,6 +438,16 @@
 	    ip_input((struct mbuf *)pkt) ;
 	    break ;
 
+	case DN_TO_IP6_IN:
+	    ip6_input((struct mbuf *)pkt) ; 
+	    break ;
+
+	case DN_TO_IP6_OUT:
+	    (void)ip6_output((struct mbuf *)pkt, NULL, NULL, 0,
+			NULL, NULL, NULL); 
+	    rt_unref (pkt->ip6opt.ro_or.ro_rt) ;
+	    break ;
+
 	case DN_TO_BDG_FWD :
 	    if (!BDG_LOADED) {
 		/* somebody unloaded the bridge module. Drop pkt */
@@ -863,37 +876,80 @@
 {
     int i = 0 ; /* we need i and q for new allocations */
     struct dn_flow_queue *q, *prev;
+    int is_v6 = IS_IP6_FLOW_ID(id);
 
     if ( !(fs->flags_fs & DN_HAVE_FLOW_MASK) )
 	q = fs->rq[0] ;
     else {
-	/* first, do the masking */
-	id->dst_ip &= fs->flow_mask.dst_ip ;
-	id->src_ip &= fs->flow_mask.src_ip ;
+	/* first, do the masking, then hash */
 	id->dst_port &= fs->flow_mask.dst_port ;
 	id->src_port &= fs->flow_mask.src_port ;
 	id->proto &= fs->flow_mask.proto ;
 	id->flags = 0 ; /* we don't care about this one */
-	/* then, hash function */
-	i = ( (id->dst_ip) & 0xffff ) ^
-	    ( (id->dst_ip >> 15) & 0xffff ) ^
-	    ( (id->src_ip << 1) & 0xffff ) ^
-	    ( (id->src_ip >> 16 ) & 0xffff ) ^
-	    (id->dst_port << 1) ^ (id->src_port) ^
-	    (id->proto );
+	if (is_v6) {
+	    APPLY_MASK(&id->dst_ip6, &fs->flow_mask.dst_ip6);
+	    APPLY_MASK(&id->src_ip6, &fs->flow_mask.src_ip6);
+	    id->flow_id6 &= fs->flow_mask.flow_id6;
+
+	    i = ((id->dst_ip6.__u6_addr.__u6_addr32[0]) & 0xffff)^
+		((id->dst_ip6.__u6_addr.__u6_addr32[1]) & 0xffff)^ 
+		((id->dst_ip6.__u6_addr.__u6_addr32[2]) & 0xffff)^
+		((id->dst_ip6.__u6_addr.__u6_addr32[3]) & 0xffff)^
+
+		((id->dst_ip6.__u6_addr.__u6_addr32[0] >> 15) & 0xffff)^
+		((id->dst_ip6.__u6_addr.__u6_addr32[1] >> 15) & 0xffff)^ 
+		((id->dst_ip6.__u6_addr.__u6_addr32[2] >> 15) & 0xffff)^
+		((id->dst_ip6.__u6_addr.__u6_addr32[3] >> 15) & 0xffff)^
+
+		((id->src_ip6.__u6_addr.__u6_addr32[0] << 1) & 0xfffff)^
+		((id->src_ip6.__u6_addr.__u6_addr32[1] << 1) & 0xfffff)^ 
+		((id->src_ip6.__u6_addr.__u6_addr32[2] << 1) & 0xfffff)^
+		((id->src_ip6.__u6_addr.__u6_addr32[3] << 1) & 0xfffff)^
+
+		((id->src_ip6.__u6_addr.__u6_addr32[0] << 16) & 0xffff)^
+		((id->src_ip6.__u6_addr.__u6_addr32[1] << 16) & 0xffff)^ 
+		((id->src_ip6.__u6_addr.__u6_addr32[2] << 16) & 0xffff)^
+		((id->src_ip6.__u6_addr.__u6_addr32[3] << 16) & 0xffff)^
+
+		(id->dst_port << 1) ^ (id->src_port) ^
+		(id->proto ) ^
+		(id->flow_id6);
+	} else {
+	    id->dst_ip &= fs->flow_mask.dst_ip ;
+	    id->src_ip &= fs->flow_mask.src_ip ;
+
+	    i = ( (id->dst_ip) & 0xffff ) ^
+		( (id->dst_ip >> 15) & 0xffff ) ^
+		( (id->src_ip << 1) & 0xffff ) ^
+		( (id->src_ip >> 16 ) & 0xffff ) ^
+		(id->dst_port << 1) ^ (id->src_port) ^
+		(id->proto );
+	}
 	i = i % fs->rq_size ;
 	/* finally, scan the current list for a match */
 	searches++ ;
 	for (prev=NULL, q = fs->rq[i] ; q ; ) {
 	    search_steps++;
-	    if (id->dst_ip == q->id.dst_ip &&
+	    if (is_v6 &&
+		    IN6_ARE_ADDR_EQUAL(&id->dst_ip6,&q->id.dst_ip6) &&
+		    IN6_ARE_ADDR_EQUAL(&id->src_ip6,&q->id.src_ip6) &&
+		    id->dst_port == q->id.dst_port &&
+		    id->src_port == q->id.src_port &&
+		    id->proto == q->id.proto &&
+		    id->flags == q->id.flags &&
+		    id->flow_id6 == q->id.flow_id6)
+		break ; /* found */
+
+	    if (!is_v6 && id->dst_ip == q->id.dst_ip &&
 		    id->src_ip == q->id.src_ip &&
 		    id->dst_port == q->id.dst_port &&
 		    id->src_port == q->id.src_port &&
 		    id->proto == q->id.proto &&
 		    id->flags == q->id.flags)
 		break ; /* found */
-	    else if (pipe_expire && q->head == NULL && q->S == q->F+1 ) {
+
+	    /* No match. Check if we can expire the entry */
+	    if (pipe_expire && q->head == NULL && q->S == q->F+1 ) {
 		/* entry is idle and not in any heap, expire it */
 		struct dn_flow_queue *old_q = q ;
 
@@ -917,7 +973,7 @@
     if (q == NULL) { /* no match, need to allocate a new entry */
 	q = create_queue(fs, i);
 	if (q != NULL)
-	q->id = *id ;
+	    q->id = *id ;
     }
     return q ;
 }
@@ -1030,7 +1086,7 @@
 {
 #if IPFW2
     struct dn_flow_set *fs;
-    ipfw_insn *cmd = rule->cmd + rule->act_ofs;
+    ipfw_insn *cmd = ACTION_PTR(rule);
 
     if (cmd->opcode == O_LOG)
 	cmd += F_LEN(cmd);
@@ -1099,7 +1155,7 @@
     int s = splimp();
     int is_pipe;
 #if IPFW2
-    ipfw_insn *cmd = fwa->rule->cmd + fwa->rule->act_ofs;
+    ipfw_insn *cmd = ACTION_PTR(fwa->rule);
 
     if (cmd->opcode == O_LOG)
 	cmd += F_LEN(cmd);
@@ -1177,6 +1233,15 @@
 
 	pkt->dn_dst = fwa->dst;
 	pkt->flags = fwa->flags;
+    } else if (dir == DN_TO_IP6_OUT) {
+	pkt->ip6opt.ro_or = fwa->dummypar.ro_or;
+	pkt->ip6opt.flags_or = fwa->dummypar.flags_or;
+	pkt->ip6opt.origifp_or = fwa->dummypar.origifp_or;
+	pkt->ip6opt.ifp_or = fwa->dummypar.ifp_or;
+	pkt->ip6opt.dst_or = fwa->dummypar.dst_or;
+	if (fwa->dummypar.ro_or.ro_rt)
+	    fwa->dummypar.ro_or.ro_rt->rt_refcnt++;
+	pkt->flags = fwa->flags;
     }
     if (q->head == NULL)
 	q->head = pkt;
@@ -1275,6 +1340,7 @@
  */
 #define DN_FREE_PKT(pkt)	{		\
 	struct dn_pkt *n = pkt ;		\
+	rt_unref ( n->ip6opt.ro_or.ro_rt ); /* XXX */	\
 	rt_unref ( n->ro.ro_rt ) ;		\
 	m_freem(n->dn_m);			\
 	pkt = DN_NEXT(n) ;			\
@@ -1937,7 +2003,7 @@
 static void
 ip_dn_init(void)
 {
-    printf("DUMMYNET initialized (011031)\n");
+    printf("DUMMYNET with IPv6 initialized (040114)\n");
     all_pipes = NULL ;
     all_flow_sets = NULL ;
     ready_heap.size = ready_heap.elements = 0 ;
--- ./originali/ip_dummynet.h	Wed Jan 14 10:35:41 2004
+++ ./sys/netinet/ip_dummynet.h	Tue Mar 23 15:15:53 2004
@@ -109,6 +109,7 @@
     struct dn_heap_entry *p ;	/* really an array of "size" entries */
 } ;
 
+#ifdef _KERNEL
 /*
  * struct dn_pkt identifies a packet in the dummynet queue, but
  * is also used to tag packets passed back to the various destinations
@@ -135,13 +136,17 @@
 #define DN_TO_BDG_FWD	3
 #define DN_TO_ETH_DEMUX	4
 #define DN_TO_ETH_OUT	5
+#define DN_TO_IP6_IN	6
+#define DN_TO_IP6_OUT	7
 
     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 ?)	*/
+    struct _ip6dn_args ip6opt;	/* XXX ipv6 options			*/
 };
+#endif /* _KERNEL */
 
 /*
  * Overall structure of dummynet (with WF2Q+):
--- ./originali/ip_fw2.c	Wed Jan 14 10:35:41 2004
+++ ./sys/netinet/ip_fw2.c	Tue Mar 23 15:15:53 2004
@@ -37,6 +37,7 @@
 #include "opt_ipdn.h"
 #include "opt_ipdivert.h"
 #include "opt_inet.h"
+#include "opt_ipsec.h"
 #ifndef INET
 #error IPFIREWALL requires INET.
 #endif /* INET */
@@ -76,6 +77,9 @@
 #include <netinet6/ipsec.h>
 #endif
 
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+
 #include <netinet/if_ether.h> /* XXX for ETHERTYPE_IP */
 
 #include <machine/in_cksum.h>	/* XXX for in_cksum */
@@ -234,14 +238,19 @@
 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
+ * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T
+ * Other macros just cast void * into the appropriate type
  */
 #define	L3HDR(T, ip) ((T *)((u_int32_t *)(ip) + (ip)->ip_hl))
+#define	TCP(p) ((struct tcphdr *)(p))
+#define	UDP(p) ((struct udphdr *)(p))
+#define	ICMP(p) ((struct icmp *)(p))
+#define ICMP6(p) ((struct icmp6_hdr *)(p))
 
 static __inline int
-icmptype_match(struct ip *ip, ipfw_insn_u32 *cmd)
+icmptype_match(struct icmp *icmp, ipfw_insn_u32 *cmd)
 {
-	int type = L3HDR(struct icmp,ip)->icmp_type;
+	int type = icmp->icmp_type;
 
 	return (type <= ICMP_MAXTYPE && (cmd->d[0] & (1<<type)) );
 }
@@ -250,9 +259,10 @@
     (1 << ICMP_TSTAMP) | (1 << ICMP_IREQ) | (1 << ICMP_MASKREQ) )
 
 static int
-is_icmp_query(struct ip *ip)
+is_icmp_query(struct icmp *icmp)
 {
-	int type = L3HDR(struct icmp, ip)->icmp_type;
+	int type = icmp->icmp_type;
+
 	return (type <= ICMP_MAXTYPE && (TT & (1<<type)) );
 }
 #undef TT
@@ -328,10 +338,9 @@
 }
 
 static int
-tcpopts_match(struct ip *ip, ipfw_insn *cmd)
+tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd)
 {
 	int optlen, bits = 0;
-	struct tcphdr *tcp = L3HDR(struct tcphdr,ip);
 	u_char *cp = (u_char *)(tcp + 1);
 	int x = (tcp->th_off << 2) - sizeof(struct tcphdr);
 
@@ -449,6 +458,83 @@
 	return 1;
 }
 
+/*
+ * ipv6 specific rules here...
+ */
+static __inline int
+icmp6type_match (int type, ipfw_insn_u32 *cmd)
+{
+	return (type <= ICMP6_MAXTYPE && (cmd->d[type/32] & (1<<(type%32)) ) );
+}
+
+static int
+flow6id_match( int curr_flow, ipfw_insn_u32 *cmd )
+{
+	int i;
+	for (i=0; i <= cmd->o.arg1; ++i )
+		if (curr_flow == cmd->d[i] )
+			return 1;
+	return 0;
+}
+
+/* support for IP6_*_ME opcodes */
+static int
+search_ip6_addr_net (struct in6_addr * ip6_addr)
+{
+	struct ifnet *mdc;
+	struct ifaddr *mdc2;
+	struct in6_ifaddr *fdm;
+	struct in6_addr copia;
+
+	TAILQ_FOREACH(mdc, &ifnet, if_link)
+		for (mdc2 = mdc->if_addrlist.tqh_first; mdc2;
+		    mdc2 = mdc2->ifa_list.tqe_next) {
+			if (!mdc2->ifa_addr)
+				continue;
+			if (mdc2->ifa_addr->sa_family == AF_INET6) {
+				fdm = (struct in6_ifaddr *)mdc2;
+				copia = fdm->ia_addr.sin6_addr;
+				/* need for leaving scope_id in the sock_addr */
+				in6_clearscope(&copia);
+				if (IN6_ARE_ADDR_EQUAL(ip6_addr, &copia))
+					return 1;
+			}
+		}
+	return 0;
+}
+
+static int
+verify_rev_path6(struct in6_addr *src, struct ifnet *ifp)
+{
+	static struct route_in6 ro;
+	struct sockaddr_in6 *dst;
+
+	dst = (struct sockaddr_in6 * )&(ro.ro_dst);
+
+	if ( !(IN6_ARE_ADDR_EQUAL (src, &dst->sin6_addr) )) {
+		bzero(dst, sizeof(*dst));
+		dst->sin6_family = AF_INET6;
+		dst->sin6_len = sizeof(*dst);
+		dst->sin6_addr = *src;
+		rtalloc_ign((struct route *)&ro, RTF_CLONING | RTF_PRCLONING);
+	}
+	if ((ro.ro_rt == NULL) || (ifp == NULL) ||
+	    (ro.ro_rt->rt_ifp->if_index != ifp->if_index))
+		return 0;
+	return 1;
+}
+static __inline int
+hash_packet6(struct ipfw_flow_id *id)
+{
+	u_int32_t i;
+	i= (id->dst_ip6.__u6_addr.__u6_addr32[0]) ^
+	(id->dst_ip6.__u6_addr.__u6_addr32[1]) ^
+	(id->dst_ip6.__u6_addr.__u6_addr32[2]) ^
+	(id->dst_ip6.__u6_addr.__u6_addr32[3]) ^
+	(id->dst_port) ^ (id->src_port) ^ (id->flow_id6);
+	return i;
+}
+/* end of ipv6 opcodes */
 
 static u_int64_t norule_counter;	/* counter for ipfw_log(NULL...) */
 
@@ -653,7 +739,9 @@
 {
 	u_int32_t i;
 
-	i = (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port);
+	i = IS_IP6_FLOW_ID(id) ? hash_packet6(id):
+		(id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port);
+
 	i &= (curr_dyn_buckets - 1);
 	return i;
 }
@@ -778,7 +866,7 @@
 
 	if (ipfw_dyn_v == NULL)
 		goto done;	/* not found */
-	i = hash_packet( pkt );
+	i = hash_packet(pkt);
 	for (prev=NULL, q = ipfw_dyn_v[i] ; q != NULL ; ) {
 		if (q->dyn_type == O_LIMIT_PARENT && q->count)
 			goto next;
@@ -788,6 +876,27 @@
 		}
 		if (pkt->proto == q->id.proto &&
 		    q->dyn_type != O_LIMIT_PARENT) {
+		      if (IS_IP6_FLOW_ID(pkt)) {
+			if (IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6),
+				&(q->id.src_ip6)) &&
+			    IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6),
+				&(q->id.dst_ip6)) &&
+			    pkt->src_port == q->id.src_port &&
+			    pkt->dst_port == q->id.dst_port ) {
+				dir = MATCH_FORWARD;
+				break;
+			}
+			if (IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6),
+				&(q->id.dst_ip6)) &&
+			    IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6),
+				&(q->id.src_ip6)) &&
+			    pkt->src_port == q->id.dst_port &&
+			    pkt->dst_port == q->id.src_port ) {
+				dir = MATCH_REVERSE;
+				break;
+			}
+
+		      } else {
 			if (pkt->src_ip == q->id.src_ip &&
 			    pkt->dst_ip == q->id.dst_ip &&
 			    pkt->src_port == q->id.src_port &&
@@ -802,6 +911,7 @@
 				dir = MATCH_REVERSE;
 				break;
 			}
+		      }
 		}
 next:
 		prev = q;
@@ -978,15 +1088,25 @@
 	int i;
 
 	if (ipfw_dyn_v) {
-		i = hash_packet( pkt );
+		int is_v6 = IS_IP6_FLOW_ID(pkt);
+		i = hash_packet(pkt);
 		for (q = ipfw_dyn_v[i] ; q != NULL ; q=q->next)
 			if (q->dyn_type == O_LIMIT_PARENT &&
 			    rule== q->rule &&
 			    pkt->proto == q->id.proto &&
-			    pkt->src_ip == q->id.src_ip &&
-			    pkt->dst_ip == q->id.dst_ip &&
 			    pkt->src_port == q->id.src_port &&
-			    pkt->dst_port == q->id.dst_port) {
+			    pkt->dst_port == q->id.dst_port &&
+			    (
+				(is_v6 &&
+				 IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6),
+					&(q->id.src_ip6)) &&
+				 IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6),
+					&(q->id.dst_ip6))) ||
+				(!is_v6 &&
+				 pkt->src_ip == q->id.src_ip &&
+				 pkt->dst_ip == q->id.dst_ip)
+			    )
+			) {
 				q->expire = time_second + dyn_short_lifetime;
 				DEB(printf("ipfw: lookup_dyn_parent found 0x%p\n",q);)
 				return q;
@@ -1052,14 +1172,21 @@
 		DEB(printf("ipfw: installing dyn-limit rule %d\n",
 		    cmd->conn_limit);)
 
-		id.dst_ip = id.src_ip = 0;
-		id.dst_port = id.src_port = 0;
+		bzero (&id, sizeof(id));
+
 		id.proto = args->f_id.proto;
 
-		if (limit_mask & DYN_SRC_ADDR)
-			id.src_ip = args->f_id.src_ip;
-		if (limit_mask & DYN_DST_ADDR)
-			id.dst_ip = args->f_id.dst_ip;
+		if (IS_IP6_FLOW_ID (&(args->f_id))) {
+			if (limit_mask & DYN_SRC_ADDR)
+				id.src_ip6 = args->f_id.src_ip6;
+			if (limit_mask & DYN_DST_ADDR)
+				id.dst_ip6 = args->f_id.dst_ip6;
+		} else {
+			if (limit_mask & DYN_SRC_ADDR)
+				id.src_ip = args->f_id.src_ip;
+			if (limit_mask & DYN_DST_ADDR)
+				id.dst_ip = args->f_id.dst_ip;
+		}
 		if (limit_mask & DYN_SRC_PORT)
 			id.src_port = args->f_id.src_port;
 		if (limit_mask & DYN_DST_PORT)
@@ -1299,12 +1426,8 @@
 	 *	consumes the packet because it calls send_reject().
 	 *	XXX This has to change, so that ipfw_chk() never modifies
 	 *	or consumes the buffer.
-	 * ip	is simply an alias of the value of m, and it is kept
-	 *	in sync with it (the packet is	supposed to start with
-	 *	the ip header).
 	 */
 	struct mbuf *m = args->m;
-	struct ip *ip = mtod(m, struct ip *);
 
 	/*
 	 * oif | args->oif	If NULL, ipfw_chk has been called on the
@@ -1321,12 +1444,12 @@
 	 * hlen	The length of the IPv4 header.
 	 *	hlen >0 means we have an IPv4 packet.
 	 */
-	u_int hlen = 0;		/* hlen >0 means we have an IP pkt */
+	u_int hlen = 0;
 
 	/*
 	 * offset	The offset of a fragment. offset != 0 means that
-	 *	we have a fragment at this offset of an IPv4 packet.
-	 *	offset == 0 means that (if this is an IPv4 packet)
+	 *	we have a fragmented ip packet.
+	 *	offset == 0 means that (if this is an IP packet)
 	 *	this is the first or only fragment.
 	 */
 	u_short offset = 0;
@@ -1350,95 +1473,197 @@
 	struct in_addr src_ip, dst_ip;		/* NOTE: network format	*/
 	u_int16_t ip_len=0;
 	int pktlen;
-	int dyn_dir = MATCH_UNKNOWN;
-	ipfw_dyn_rule *q = NULL;
 
-	if (m->m_flags & M_SKIP_FIREWALL)
-		return 0;	/* accept */
 	/*
 	 * dyn_dir = MATCH_UNKNOWN when rules unchecked,
 	 * 	MATCH_NONE when checked and not matched (q = NULL),
 	 *	MATCH_FORWARD or MATCH_REVERSE otherwise (q != NULL)
 	 */
-
-	pktlen = m->m_pkthdr.len;
-	if (args->eh == NULL ||		/* layer 3 packet */
-		( m->m_pkthdr.len >= sizeof(struct ip) &&
-		    ntohs(args->eh->ether_type) == ETHERTYPE_IP))
-			hlen = ip->ip_hl << 2;
+	int dyn_dir = MATCH_UNKNOWN;
+	ipfw_dyn_rule *q = NULL;
 
 	/*
-	 * Collect parameters into local variables for faster matching.
+	 * We store in ulp a pointer to the upper layer protocol header.
+	 * In the ipv4 case this is easy to determine from the header,
+	 * but for ipv6 we might have some additional headers in the middle.
+	 * ulp is NULL if not found.
 	 */
-	if (hlen == 0) {	/* do not grab addresses for non-ip pkts */
-		proto = args->f_id.proto = 0;	/* mark f_id invalid */
-		goto after_ip_checks;
-	}
+	void *ulp = NULL;		/* upper layer protocol pointer. */
+
+	/* XXX ipv6 variables */
+	int is_ipv6 = 0;
+	u_int16_t ext_hd = 0;   /* bits vector for extension header filtering */
+	/* end of ipv6 variables */
+
+	if (m->m_flags & M_SKIP_FIREWALL)
+		return 0;	/* accept */
+	pktlen = m->m_pkthdr.len;
+	proto = args->f_id.proto = 0;	/* mark f_id invalid */
+
+	/* Identify ipv6 packets and fill up variables. */
+	if (pktlen >= sizeof(struct ip6_hdr) &&
+		(!args->eh || ntohs(args->eh->ether_type)==ETHERTYPE_IPV6) &&
+		mtod(m, struct ip *)->ip_v == 6) {
+
+	    is_ipv6 = 1;
+	    args->f_id.addr_type = 6;
+	    hlen = sizeof(struct ip6_hdr);
+	    proto = mtod(m, struct ip6_hdr *)->ip6_nxt;
+	    args->f_id.src_ip6 = (mtod(m, struct ip6_hdr *))->ip6_src;
+	    args->f_id.dst_ip6 = (mtod(m, struct ip6_hdr *))->ip6_dst;
+	    args->f_id.src_ip = 0;
+	    args->f_id.dst_ip = 0;
+	    args->f_id.flow_id6 = ntohs(mtod(m, struct ip6_hdr *)->ip6_flow);
+
+	    /* XXX where do we find ip_len ??? how do we set pktlen ? */
+
+	    /*
+	     * PULLUP6(len, p, T) makes sure that len + sizeof(T) is
+	     * contiguous, then it sets p to point at the offset "len" in
+	     * the mbuf. WARNING: the pointer might become stale after
+	     * other pullups (but we never use it this way).
+	     */
+#define PULLUP6(len, p, T)						\
+		do {							\
+		    int x = (len) + sizeof(T);				\
+		    if ((m)->m_len < x) {				\
+			args->m = m = m_pullup(m, x);			\
+			if (m == 0)					\
+			    goto pullup_failed;				\
+		    }							\
+		    p = (mtod(m, char *) + (len));			\
+		} while (0)
+
+	    /* Search extension headers to find upper layer protocols */
+	    while (ulp == NULL) {
+		switch (proto) {
+		case IPPROTO_ICMPV6:
+		    PULLUP6(hlen, ulp, struct icmp6_hdr);
+		    args->f_id.flags = ICMP6(ulp)->icmp6_type;
+		    break;
+
+		case IPPROTO_TCP:
+		    PULLUP6(hlen, ulp, struct tcphdr);
+		    dst_port = TCP(ulp)->th_dport;
+		    src_port = TCP(ulp)->th_sport;
+		    args->f_id.flags = TCP(ulp)->th_flags;
+		    break;
 
-	proto = args->f_id.proto = ip->ip_p;
-	src_ip = ip->ip_src;
-	dst_ip = ip->ip_dst;
-	if (args->eh != NULL) { /* layer 2 packets are as on the wire */
+		case IPPROTO_UDP:
+		    PULLUP6(hlen, ulp, struct udphdr);
+		    dst_port = UDP(ulp)->uh_dport;
+		    src_port = UDP(ulp)->uh_sport;
+		    break;
+
+		case IPPROTO_HOPOPTS:
+		    PULLUP6(hlen, ulp, struct ip6_hbh);
+		    ext_hd |= EXT_HOPOPTS;
+		    hlen += sizeof(struct ip6_hbh);
+		    proto = ((struct ip6_hbh *)ulp)->ip6h_nxt;
+		    ulp = NULL;
+		    break;
+
+		case IPPROTO_ROUTING:
+		    PULLUP6(hlen, ulp, struct ip6_rthdr);
+		    ext_hd |= EXT_ROUTING;
+		    hlen += sizeof(struct ip6_rthdr);
+		    proto = ((struct ip6_rthdr *)ulp)->ip6r_nxt;
+		    ulp = NULL;
+		    break;
+
+		case IPPROTO_FRAGMENT:
+		    PULLUP6(hlen, ulp, struct ip6_frag);
+		    ext_hd |= EXT_FRAGMENT;
+		    hlen += sizeof (struct ip6_frag);
+		    proto = ((struct ip6_frag *)ulp)->ip6f_nxt;
+		    offset = 1;
+		    ulp = NULL; /* XXX is it correct ? */
+		    break;
+
+		case IPPROTO_AH:
+		case IPPROTO_NONE:
+		case IPPROTO_ESP:
+		    PULLUP6(hlen, ulp, struct ip6_ext);
+		    if (proto == IPPROTO_AH)
+			ext_hd |= EXT_AH;
+		    else if (proto == IPPROTO_ESP)
+			ext_hd |= EXT_ESP;
+		    hlen += ((struct ip6_ext *)ulp)->ip6e_len +
+				    sizeof (struct ip6_ext);
+		    proto = ((struct ip6_ext *)ulp)->ip6e_nxt;
+		    ulp = NULL;
+		    break;
+
+		default:
+		    printf("IPFW2: IPV6 - Unknown Extension Header (%d)\n",
+			 proto);
+		    return 0; /* deny */
+		    break;
+		} /*switch */
+	    }
+
+	    /* hlen != 0 is used to detect ipv4 packets, so clear it now */
+	    hlen = 0; /* XXX why? we have args->f_id.addr_type ... */
+
+	} else if (pktlen >= sizeof(struct ip) &&
+		(!args->eh || ntohs(args->eh->ether_type) == ETHERTYPE_IP) &&
+		mtod(m, struct ip *)->ip_v == 4) {
+	    struct ip *ip = mtod(m, struct ip *);
+
+	    hlen = ip->ip_hl << 2;
+	    args->f_id.addr_type = 4;
+
+	    /*
+	     * Collect parameters into local variables for faster matching.
+	     */
+
+	    proto = ip->ip_p;
+	    src_ip = ip->ip_src;
+	    dst_ip = ip->ip_dst;
+	    if (args->eh != NULL) { /* layer 2 packets are as on the wire */
 		offset = ntohs(ip->ip_off) & IP_OFFMASK;
 		ip_len = ntohs(ip->ip_len);
-	} else {
+	    } else {
 		offset = ip->ip_off & IP_OFFMASK;
 		ip_len = ip->ip_len;
-	}
-	pktlen = ip_len < pktlen ? ip_len : pktlen;
-
-#define PULLUP_TO(len)						\
-		do {						\
-			if ((m)->m_len < (len)) {		\
-			    args->m = m = m_pullup(m, (len));	\
-			    if (m == 0)				\
-				goto pullup_failed;		\
-			    ip = mtod(m, struct ip *);		\
-			}					\
-		} while (0)
+	    }
+	    pktlen = ip_len < pktlen ? ip_len : pktlen;
 
-	if (offset == 0) {
+	    if (offset == 0) {
 		switch (proto) {
 		case IPPROTO_TCP:
-		    {
-			struct tcphdr *tcp;
-
-			PULLUP_TO(hlen + sizeof(struct tcphdr));
-			tcp = L3HDR(struct tcphdr, ip);
-			dst_port = tcp->th_dport;
-			src_port = tcp->th_sport;
-			args->f_id.flags = tcp->th_flags;
-			}
+			PULLUP6(hlen, ulp, struct tcphdr);
+			dst_port = TCP(ulp)->th_dport;
+			src_port = TCP(ulp)->th_sport;
+			args->f_id.flags = TCP(ulp)->th_flags;
 			break;
 
 		case IPPROTO_UDP:
-		    {
-			struct udphdr *udp;
-
-			PULLUP_TO(hlen + sizeof(struct udphdr));
-			udp = L3HDR(struct udphdr, ip);
-			dst_port = udp->uh_dport;
-			src_port = udp->uh_sport;
-			}
+			PULLUP6(hlen, ulp, struct udphdr);
+			dst_port = UDP(ulp)->uh_dport;
+			src_port = UDP(ulp)->uh_sport;
 			break;
 
 		case IPPROTO_ICMP:
-			PULLUP_TO(hlen + 4);	/* type, code and checksum. */
-			args->f_id.flags = L3HDR(struct icmp, ip)->icmp_type;
+			/* we only care for 4 bytes: type, code, checksum */
+			PULLUP6(hlen, ulp, struct icmp);
+			args->f_id.flags = ICMP(ulp)->icmp_type;
 			break;
 
 		default:
 			break;
 		}
-#undef PULLUP_TO
-	}
+	    }
 
-	args->f_id.src_ip = ntohl(src_ip.s_addr);
-	args->f_id.dst_ip = ntohl(dst_ip.s_addr);
-	args->f_id.src_port = src_port = ntohs(src_port);
-	args->f_id.dst_port = dst_port = ntohs(dst_port);
+	    args->f_id.src_ip = ntohl(src_ip.s_addr);
+	    args->f_id.dst_ip = ntohl(dst_ip.s_addr);
+	}
+	if (proto) { /* we may have port numbers, store them */
+	    args->f_id.proto = proto;
+	    args->f_id.src_port = src_port = ntohs(src_port);
+	    args->f_id.dst_port = dst_port = ntohs(dst_port);
+	}
 
-after_ip_checks:
 	if (args->rule) {
 		/*
 		 * Packet has already been tagged. Look for the next rule
@@ -1531,13 +1756,11 @@
 
 			case O_GID:
 			case O_UID:
-				/*
-				 * We only check offset == 0 && proto != 0,
-				 * as this ensures that we have an IPv4
-				 * packet with the ports info.
-				 */
-				if (offset!=0)
+				if (offset != 0) /* no port info available */
+					break;
+				if (is_ipv6) /* XXX to be fixed later */
 					break;
+				/* the check for proto is below */
 			    {
 				struct inpcbinfo *pi;
 				int wildcard;
@@ -1623,7 +1846,7 @@
 				break;
 
 			case O_FRAG:
-				match = (hlen > 0 && offset != 0);
+				match = offset != 0;
 				break;
 
 			case O_IN:	/* "out" is "not in" */
@@ -1708,7 +1931,7 @@
 			case O_IP_DSTPORT:
 				/*
 				 * offset == 0 && proto != 0 is enough
-				 * to guarantee that we have an IPv4
+				 * to guarantee that we have a
 				 * packet with port info.
 				 */
 				if ((proto==IPPROTO_UDP || proto==IPPROTO_TCP)
@@ -1728,15 +1951,25 @@
 
 			case O_ICMPTYPE:
 				match = (offset == 0 && proto==IPPROTO_ICMP &&
-				    icmptype_match(ip, (ipfw_insn_u32 *)cmd) );
+				    icmptype_match(ICMP(ulp), (ipfw_insn_u32 *)cmd) );
+				break;
+
+			case O_ICMP6TYPE:
+				match = is_ipv6 && offset == 0 &&
+				    proto==IPPROTO_ICMPV6 &&
+				    icmp6type_match(
+					((struct icmp6_hdr *)ulp)->icmp6_type,
+					(ipfw_insn_u32 *)cmd);
 				break;
 
 			case O_IPOPT:
-				match = (hlen > 0 && ipopts_match(ip, cmd) );
+				match = (hlen > 0 &&
+				    ipopts_match(mtod(m, struct ip *), cmd) );
 				break;
 
 			case O_IPVER:
-				match = (hlen > 0 && cmd->arg1 == ip->ip_v);
+				match = (hlen > 0 &&
+					cmd->arg1 == mtod(m, struct ip *)->ip_v);
 				break;
 
 			case O_IPID:
@@ -1750,9 +1983,9 @@
 				    if (cmd->opcode == O_IPLEN)
 					x = ip_len;
 				    else if (cmd->opcode == O_IPTTL)
-					x = ip->ip_ttl;
+					x = mtod(m, struct ip *)->ip_ttl;
 				    else /* must be IPID */
-					x = ntohs(ip->ip_id);
+					x = ntohs(mtod(m, struct ip *)->ip_id);
 				    if (cmdlen == 1) {
 					match = (cmd->arg1 == x);
 					break;
@@ -1767,49 +2000,47 @@
 
 			case O_IPPRECEDENCE:
 				match = (hlen > 0 &&
-				    (cmd->arg1 == (ip->ip_tos & 0xe0)) );
+				    (cmd->arg1 == (mtod(m, struct ip *)->ip_tos & 0xe0)) );
 				break;
 
 			case O_IPTOS:
 				match = (hlen > 0 &&
-				    flags_match(cmd, ip->ip_tos));
+				    flags_match(cmd, mtod(m, struct ip *)->ip_tos));
 				break;
 
 			case O_TCPFLAGS:
-				match = (proto == IPPROTO_TCP && offset == 0 &&
-				    flags_match(cmd,
-					L3HDR(struct tcphdr,ip)->th_flags));
+				match = proto == IPPROTO_TCP && offset == 0 &&
+				    flags_match(cmd, TCP(ulp)->th_flags);
 				break;
 
 			case O_TCPOPTS:
-				match = (proto == IPPROTO_TCP && offset == 0 &&
-				    tcpopts_match(ip, cmd));
+				match = proto == IPPROTO_TCP && offset == 0 &&
+				    tcpopts_match(TCP(ulp), cmd);
 				break;
 
 			case O_TCPSEQ:
-				match = (proto == IPPROTO_TCP && offset == 0 &&
+				match = proto == IPPROTO_TCP && offset == 0 &&
 				    ((ipfw_insn_u32 *)cmd)->d[0] ==
-					L3HDR(struct tcphdr,ip)->th_seq);
+					TCP(ulp)->th_seq;
 				break;
 
 			case O_TCPACK:
-				match = (proto == IPPROTO_TCP && offset == 0 &&
+				match = proto == IPPROTO_TCP && offset == 0 &&
 				    ((ipfw_insn_u32 *)cmd)->d[0] ==
-					L3HDR(struct tcphdr,ip)->th_ack);
+					TCP(ulp)->th_ack;
 				break;
 
 			case O_TCPWIN:
-				match = (proto == IPPROTO_TCP && offset == 0 &&
-				    cmd->arg1 ==
-					L3HDR(struct tcphdr,ip)->th_win);
+				match = proto == IPPROTO_TCP && offset == 0 &&
+				    cmd->arg1 == TCP(ulp)->th_win;
 				break;
 
 			case O_ESTAB:
 				/* reject packets which have SYN only */
 				/* XXX should i also check for TH_ACK ? */
-				match = (proto == IPPROTO_TCP && offset == 0 &&
-				    (L3HDR(struct tcphdr,ip)->th_flags &
-				     (TH_RST | TH_ACK | TH_SYN)) != TH_SYN);
+				match = proto == IPPROTO_TCP && offset == 0 &&
+				    ( TCP(ulp)->th_flags &
+				     (TH_RST | TH_ACK | TH_SYN)) != TH_SYN;
 				break;
 
 			case O_LOG:
@@ -1824,8 +2055,11 @@
 
 			case O_VERREVPATH:
 				/* Outgoing packets automatically pass/match */
-				match = ((oif != NULL) ||
+				match = (oif != NULL) ||
 				    (m->m_pkthdr.rcvif == NULL) ||
+				    (is_ipv6 ?
+					verify_rev_path6(&(args->f_id.src_ip6),
+						m->m_pkthdr.rcvif) :
 				    verify_rev_path(src_ip, m->m_pkthdr.rcvif));
 				break;
 
@@ -1840,6 +2074,63 @@
 				/* otherwise no match */
 				break;
 
+			case O_IP6_SRC:
+			
+				match = is_ipv6 &&
+					IN6_ARE_ADDR_EQUAL(&args->f_id.src_ip6,
+					    &((ipfw_insn_ip6 *)cmd)->addr6);
+/*					    printf("Match = %d - isip6 = %d - srcAddr = %d,%d,%d,%d - cmdAddr = %d,%d,%d,%d\n", match, is_ipv6, args->f_id.src_ip6.s6_addr32[0], args->f_id.src_ip6.s6_addr32[1], args->f_id.src_ip6.s6_addr32[2], args->f_id.src_ip6.s6_addr32[3], ((ipfw_insn_ip6 *)cmd->addr6).s6_addr32[0], ((ipfw_insn_ip6 *)cmd->addr6).s6_addr32[1],((ipfw_insn_ip6 *)cmd->addr6).s6_addr32[2], ((ipfw_insn_ip6 *)cmd->addr6).s6_addr32[3]); */
+				break;
+
+			case O_IP6_DST:
+				match = is_ipv6 &&
+					IN6_ARE_ADDR_EQUAL(&args->f_id.dst_ip6,
+					    &((ipfw_insn_ip6 *)cmd)->addr6);
+			        break;
+
+			case O_IP6_SRC_MASK:
+				if (is_ipv6) {
+				    ipfw_insn_ip6 *te = (ipfw_insn_ip6 *)cmd;
+				    struct in6_addr p = args->f_id.src_ip6;
+
+				    APPLY_MASK(&p, &te->mask6);
+				    match = IN6_ARE_ADDR_EQUAL(&te->addr6, &p);
+				}
+				break;
+
+			case O_IP6_DST_MASK:
+				if (is_ipv6) {
+				    ipfw_insn_ip6 *te = (ipfw_insn_ip6 *)cmd;
+				    struct in6_addr p = args->f_id.dst_ip6;
+
+				    APPLY_MASK(&p, &te->mask6);
+				    match = IN6_ARE_ADDR_EQUAL(&te->addr6, &p);
+				}
+				break;
+
+			case O_IP6_SRC_ME:
+				match= is_ipv6 && search_ip6_addr_net(&args->f_id.src_ip6);
+				break;
+
+			case O_IP6_DST_ME:
+				match= is_ipv6 && search_ip6_addr_net(&args->f_id.dst_ip6);
+				break;
+
+			case O_FLOW6ID:
+				match = is_ipv6 &&
+					flow6id_match(args->f_id.flow_id6,
+						(ipfw_insn_u32 *) cmd);
+				break;
+
+			case O_EXT_HDR:
+				match = is_ipv6 &&
+				    (ext_hd & ((ipfw_insn *) cmd)->arg1);
+				break;
+
+			case O_IP6:
+				match = is_ipv6;
+				break;
+
 			/*
 			 * The second set of opcodes represents 'actions',
 			 * i.e. the terminal part of a rule once the packet
@@ -1902,7 +2193,7 @@
 				if (dyn_dir == MATCH_UNKNOWN &&
 				    (q = lookup_dyn_rule(&args->f_id,
 				     &dyn_dir, proto == IPPROTO_TCP ?
-					L3HDR(struct tcphdr, ip) : NULL))
+						TCP(ulp) : NULL))
 					!= NULL) {
 					/*
 					 * Found dynamic entry, update stats
@@ -1967,9 +2258,9 @@
 				 */
 				if (hlen > 0 &&
 				    (proto != IPPROTO_ICMP ||
-				     is_icmp_query(ip)) &&
+				     is_icmp_query(ICMP(ulp))) &&
 				    !(m->m_flags & (M_BCAST|M_MCAST)) &&
-				    !IN_MULTICAST(dst_ip.s_addr)) {
+				    !IN_MULTICAST(ntohl(dst_ip.s_addr))) {
 					send_reject(args, cmd->arg1,
 					    offset,ip_len);
 					m = args->m;
@@ -2414,6 +2705,10 @@
 		case O_ESTAB:
 		case O_VERREVPATH:
 		case O_IPSEC:
+		case O_IP6_SRC_ME:
+		case O_IP6_DST_ME:
+		case O_EXT_HDR:
+		case O_IP6:
 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
 				goto bad_size;
 			break;
@@ -2527,6 +2822,29 @@
 				return EINVAL;
 			}
 			break;
+
+		case O_IP6_SRC:
+		case O_IP6_DST:
+			if (cmdlen != F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))
+				goto bad_size;
+			break;
+
+		case O_FLOW6ID:
+			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
+					((ipfw_insn_u32 *)cmd)->o.arg1)
+				goto bad_size;
+			break;
+
+		case O_IP6_SRC_MASK:
+		case O_IP6_DST_MASK:
+			if ( !(cmdlen & 1) || cmdlen > 127)
+				goto bad_size;
+			break;
+		case O_ICMP6TYPE:
+			if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) )
+				goto bad_size;
+			break;
+
 		default:
 			printf("ipfw: opcode %d, unknown opcode\n",
 				cmd->opcode);
@@ -2796,7 +3114,7 @@
 	add_rule(&layer3_chain, &default_rule);
 
 	ip_fw_default_rule = layer3_chain;
-	printf("ipfw2 initialized, divert %s, "
+	printf("ipfw2 (+ipv6) initialized, divert %s, "
 		"rule-based forwarding enabled, default to %s, logging ",
 #ifdef IPDIVERT
 		"enabled",
--- ./originali/ip_fw2.h	Wed Jan 14 10:35:41 2004
+++ ./sys/netinet/ip_fw2.h	Tue Mar 23 15:15:53 2004
@@ -126,10 +126,32 @@
 	 */
 	O_IPSEC,		/* has ipsec history		*/
 
+	O_IP6_SRC,              /* address without mask */
+	O_IP6_SRC_ME,           /* my addresses */
+	O_IP6_SRC_MASK,         /* address with the mask        */
+	O_IP6_DST,
+	O_IP6_DST_ME,
+	O_IP6_DST_MASK,
+	O_FLOW6ID,              /* for flow id tag in the ipv6 pkt */
+	O_ICMP6TYPE,            /* icmp6 packet type filtering */
+	O_EXT_HDR,              /* filtering for ipv6 extension header */
+	O_IP6,
+
 	O_LAST_OPCODE		/* not an opcode!		*/
 };
 
 /*
+ * The extension header are filtered only for presence using a bit vector
+ * with a flag for each header.
+ */
+
+#define	EXT_FRAGMENT	0x1
+#define	EXT_HOPOPTS	0x2
+#define	EXT_ROUTING	0x4
+#define	EXT_AH		0x8
+#define	EXT_ESP		0x10
+
+/*
  * Template for instructions.
  *
  * ipfw_insn is used for all instructions which require no operands,
@@ -265,6 +287,30 @@
 	u_int32_t log_left;	/* how many left to log 	*/
 } ipfw_insn_log;
 
+/* Apply ipv6 mask on ipv6 addr */
+#define APPLY_MASK(addr,mask)				\
+    (addr)->__u6_addr.__u6_addr32[0] &= (mask)->__u6_addr.__u6_addr32[0]; \
+    (addr)->__u6_addr.__u6_addr32[1] &= (mask)->__u6_addr.__u6_addr32[1]; \
+    (addr)->__u6_addr.__u6_addr32[2] &= (mask)->__u6_addr.__u6_addr32[2]; \
+    (addr)->__u6_addr.__u6_addr32[3] &= (mask)->__u6_addr.__u6_addr32[3];
+
+/* Structure for ipv6 */
+typedef struct _ipfw_insn_ip6 {
+	ipfw_insn o;
+	struct in6_addr addr6;
+	struct in6_addr mask6;
+} ipfw_insn_ip6;
+
+/* Used to support icmp6 types */
+typedef struct _ipfw_insn_icmp6 {
+	ipfw_insn o;
+	uint32_t d[7]; /* XXX This number si related to the netinet/icmp6.h
+	                *     define ICMP6_MAXTYPE
+	                *     as follows: n = ICMP6_MAXTYPE/32 + 1
+                        *     Actually is 203 
+			*/
+} ipfw_insn_icmp6;
+
 /*
  * Here we have the structure representing an ipfw rule.
  *
@@ -327,8 +373,15 @@
 	u_int16_t	src_port;
 	u_int8_t	proto;
 	u_int8_t	flags;	/* protocol-specific flags */
+	uint8_t		addr_type; /* 4 = ipv4, 6 = ipv6, 1=ether ? */
+	uint8_t		_pad;
+	struct in6_addr dst_ip6;	/* could also store MAC addr! */
+	struct in6_addr src_ip6;
+	u_int32_t       flow_id6;
 };
 
+#define	IS_IP6_FLOW_ID(id)	((id)->addr_type == 6)
+
 /*
  * Dynamic ipfw rule.
  */
@@ -383,6 +436,17 @@
 #define	IP_FW_PORT_TEE_FLAG	0x20000
 #define	IP_FW_PORT_DENY_FLAG	0x40000
 
+/* 
+ * Structure for collecting parameters to dummynet for ip6_output forwarding
+ */
+struct	_ip6dn_args {
+	struct route_in6 ro_or;
+	int flags_or;
+	struct ifnet *origifp_or;
+	struct ifnet *ifp_or;
+	struct sockaddr_in6 dst_or;
+};
+
 /*
  * Arguments for calling ipfw_chk() and dummynet_io(). We put them
  * all into a structure because this way it is easier and more
@@ -402,6 +466,8 @@
 	struct ipfw_flow_id f_id;	/* grabbed from IP header	*/
 	u_int16_t	divert_rule;	/* divert cookie		*/
 	u_int32_t	retval;
+
+	struct _ip6dn_args	dummypar; /* dummynet->ip6_output */
 };
 
 /*
--- ./originali/ip_output.c	Wed Jan 14 10:38:41 2004
+++ ./sys/netinet/ip_output.c	Tue Mar 23 15:15:53 2004
@@ -996,6 +996,32 @@
 				ip->ip_sum = in_cksum(m, hlen);
 			}
 		}
+#if 1		/* SRCSINK
+		 * Bits 30..16 of flags are a count used to send up to count-1
+		 * additional copies of the packet, and then continue inline.
+		 */
+		off = (flags >> 16) & 0xffff; /* replica count */
+		if (off > 1) {
+		    int s, sent = 0;
+		    struct mbuf *mine;
+
+		    for (;off > 1; off--) {
+			s = splimp();
+			mine = m_copypacket(m, M_DONTWAIT);
+			splx(s);
+			error = (mine == NULL) ? ENOBUFS :
+				    (*ifp->if_output)(ifp, mine,
+					(struct sockaddr *)dst, ro->ro_rt);
+			if (error != 0)
+			    break;
+			sent++;
+		    }
+		    if (!(flags & IP_FORWARDING) && ia) {
+			    ia->ia_ifa.if_opackets += sent;
+			    ia->ia_ifa.if_obytes += sent*m->m_pkthdr.len;
+		    }
+		}
+#endif		/* SRCSINK */
 
 		/* Record statistics for this interface address. */
 		if (!(flags & IP_FORWARDING) && ia) {
@@ -1568,6 +1594,24 @@
 			switch (sopt->sopt_name) {
 
 			case IP_TOS:
+#if 1	/* SRCSINK
+	 * getsockopt(IP_TOS) with a value above 0xff is used as follows:
+	 * + bit 23 sets/clear behaviour as a sink (goes into bit 15
+	 *   of inp_inc.inc_pad;
+	 * + bits 22..8 are the replica count (bit 14-0 of inp_inc.inc_pad)
+	 * copy back the number complemented so the caller knows this
+	 * is handled specially.
+	 */
+				error = sooptcopyin(sopt, &optval,
+					    sizeof optval, sizeof optval);
+				if (error)
+					break;
+				if (optval > 0xff) {
+					inp->inp_inc.inc_pad =
+					    (optval >> 8) & 0xffff;
+					optval = ~optval;
+				} else
+#endif	/* SRCSINK */
 				optval = inp->inp_ip_tos;
 				break;
 
--- ./originali/ipfw2.c	Wed Jan 14 10:48:23 2004
+++ ./sbin/ipfw/ipfw2.c	Tue Mar 23 15:15:54 2004
@@ -53,6 +53,7 @@
 #include <netinet/ip_dummynet.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
+#include <netinet/icmp6.h>
 
 int
 		do_resolv,		/* Would try to resolve all */
@@ -243,6 +244,13 @@
 	TOK_DROPTAIL,
 	TOK_PROTO,
 	TOK_WEIGHT,
+
+	TOK_IPV6,
+	TOK_FLOWID,
+	TOK_ICMP6TYPES,
+	TOK_EXT6HDR,
+	TOK_DSTIP6,
+	TOK_SRCIP6,
 };
 
 struct _s_x dummynet_params[] = {
@@ -265,6 +273,13 @@
 	{ "delay",		TOK_DELAY },
 	{ "pipe",		TOK_PIPE },
 	{ "queue",		TOK_QUEUE },
+
+	{ "flow-id",		TOK_FLOWID},
+	{ "dst-ipv6",		TOK_DSTIP6},
+	{ "dst-ip6",		TOK_DSTIP6},
+	{ "src-ipv6",		TOK_SRCIP6},
+	{ "src-ip6",		TOK_SRCIP6},
+
 	{ "dummynet-params",	TOK_NULL },
 	{ NULL, 0 }	/* terminator */
 };
@@ -339,6 +354,16 @@
 	{ "ipsec",		TOK_IPSEC },
 	{ "//",			TOK_COMMENT },
 
+	{ "icmp6type",		TOK_ICMP6TYPES },
+	{ "icmp6types",		TOK_ICMP6TYPES },
+	{ "ext6hdr",		TOK_EXT6HDR},
+	{ "flow-id",		TOK_FLOWID},
+	{ "ipv6",		TOK_IPV6},
+	{ "dst-ipv6",		TOK_DSTIP6},
+	{ "dst-ip6",		TOK_DSTIP6},
+	{ "src-ipv6",		TOK_SRCIP6},
+	{ "src-ip6",		TOK_SRCIP6},
+
 	{ "not",		TOK_NOT },		/* pseudo option */
 	{ "!", /* escape ? */	TOK_NOT },		/* pseudo option */
 	{ "or",			TOK_OR },		/* pseudo option */
@@ -826,6 +851,197 @@
 	}
 }
 
+/* XXX ipv6 stuff */
+/* 
+ * Print the ip address contained in a command.
+ */
+static void
+print_ip6(ipfw_insn_ip6 *cmd, char const *s)
+{
+	struct hostent *he = NULL;
+	int len = F_LEN((ipfw_insn *) cmd) - 1;
+	struct in6_addr *a = &(cmd->addr6);
+	char trad[255];
+
+	printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
+
+	if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) {
+		printf("me6");
+		return;
+	}
+	if (cmd->o.opcode == O_IP6) {
+		printf(" ipv6");
+		return;
+	}
+
+	/*
+	 * len == 4 indicates a single IP, whereas lists of 1 or more
+	 * addr/mask pairs have len = (2n+1). We convert len to n so we
+	 * use that to count the number of entries.
+	 */
+
+	for (len = len / 4; len > 0; len -= 2, a += 2) {
+	    int mb =        /* mask length */
+		(cmd->o.opcode == O_IP6_SRC || cmd->o.opcode == O_IP6_DST) ?
+		128 : contigmask((uint8_t *)&(a[1]), 128);
+
+	    if (mb == 128 && do_resolv)
+		he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6);
+	    if (he != NULL)		/* resolved to name */
+		printf("%s", he->h_name);
+	    else if (mb == 0)		/* any */
+		printf("any");
+	    else {          /* numeric IP followed by some kind of mask */
+		if (inet_ntop(AF_INET6,  a, trad, sizeof( trad ) ) == NULL)
+		    printf("Error ntop in print_ip6\n");
+		printf("%s",  trad );
+		if (mb < 0)	/* XXX not really legal... */
+		    printf(":%s",
+			inet_ntop(AF_INET6, &a[1], trad, sizeof(trad)));
+		else if (mb < 128)
+		    printf("/%d", mb);
+	    }
+	    if (len > 2)
+		printf(",");
+	}
+}
+
+static void
+fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av)
+{
+	uint8_t type;
+
+	cmd->d[0] = 0;
+	while (*av) {
+	    if (*av == ',')
+		av++;
+	    type = strtoul(av, &av, 0);
+	    if (*av != ',' && *av != '\0')
+		errx(EX_DATAERR, "invalid ICMP6 type");
+	    if (type > ICMP6_MAXTYPE)
+		errx(EX_DATAERR, "ICMP6 type out of range");
+	    cmd->d[type / 32] |= ( 1 << (type % 32));
+	}
+	cmd->o.opcode = O_ICMP6TYPE;
+	cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6);
+}
+
+
+static void
+print_icmp6types(ipfw_insn_u32 *cmd)
+{
+	int i, j;
+	char sep= ' ';
+
+	printf(" ipv6 icmp6types");
+	for (i = 0; i < 7; i++)
+		for (j=0; j < 32; ++j) {
+			if ( (cmd->d[i] & (1 << (j))) == 0)
+				continue;
+			printf("%c%d", sep, (i*32 + j));
+			sep = ',';
+		}
+}
+
+static void
+print_flow6id( ipfw_insn_u32 *cmd)
+{
+	uint16_t i, limit = cmd->o.arg1;
+	char sep = ',';
+
+	printf(" flow-id ");
+	for( i=0; i < limit; ++i) {
+		if (i == limit - 1)
+			sep = ' ';
+		printf("%d%c", cmd->d[i], sep);
+	}
+}
+
+/* structure and define for the extension header in ipv6 */
+static struct _s_x ext6hdrcodes[] = {
+	{ "frag",	EXT_FRAGMENT },
+	{ "hopopt",	EXT_HOPOPTS },
+	{ "route",	EXT_ROUTING },
+	{ "ah",		EXT_AH },
+	{ "esp",	EXT_ESP },
+	{ NULL,		0 }
+};
+
+/* fills command for the extension header filtering */
+int
+fill_ext6hdr( ipfw_insn *cmd, char *av)
+{
+	int tok;
+	char *s = av;
+
+	cmd->arg1 = 0;
+
+	while(s) {
+	    av = strsep( &s, ",") ;
+	    tok = match_token(ext6hdrcodes, av);
+	    switch (tok) {
+	    case EXT_FRAGMENT:
+		cmd->arg1 |= EXT_FRAGMENT;
+		break;
+
+	    case EXT_HOPOPTS:
+		cmd->arg1 |= EXT_HOPOPTS;
+		break;
+
+	    case EXT_ROUTING:
+		cmd->arg1 |= EXT_ROUTING;
+		break;
+
+	    case EXT_AH:
+		cmd->arg1 |= EXT_AH;
+		break;
+
+	    case EXT_ESP:
+		cmd->arg1 |= EXT_ESP;
+		break;
+
+	    default:
+		errx( EX_DATAERR, "invalid option for ipv6 exten
+		headear" );
+		break;
+	    }
+	}
+	if (cmd->arg1 == 0 )
+	    return 0;
+	cmd->opcode = O_EXT_HDR;
+	cmd->len |= F_INSN_SIZE( ipfw_insn );
+	return 1;
+}
+
+void
+print_ext6hdr( ipfw_insn *cmd )
+{
+	char sep = ' ';
+
+	printf(" extension header:");
+	if (cmd->arg1 & EXT_FRAGMENT ) {
+	    printf("%cfragmentation", sep);
+	    sep = ',';
+	}
+	if (cmd->arg1 & EXT_HOPOPTS ) {
+	    printf("%chop options", sep);
+	    sep = ',';
+	}
+	if (cmd->arg1 & EXT_ROUTING ) {
+	    printf("%crouting options", sep);
+	    sep = ',';
+	}
+	if (cmd->arg1 & EXT_AH ) {
+	    printf("%cauthentication header", sep);
+	    sep = ',';
+	}
+	if (cmd->arg1 & EXT_ESP ) {
+	    printf("%cencapsulated security payload", sep);
+	}
+}
+
+/* XXX end of ipv6 stuff */
+
 /*
  * show_ipfw() prints the body of an ipfw rule.
  * Because the standard rule has at least proto src_ip dst_ip, we use
@@ -844,6 +1060,7 @@
 #define	HAVE_DSTIP	0x0004
 #define	HAVE_MAC	0x0008
 #define	HAVE_MACTYPE	0x0010
+#define	HAVE_PROTO6	0x0080
 #define	HAVE_OPTIONS	0x8000
 
 #define	HAVE_IP		(HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
@@ -864,6 +1081,8 @@
 		return;
 	}
 	if ( !(*flags & HAVE_OPTIONS)) {
+		if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO6))
+			printf(" ipv6");
 		if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO))
 			printf(" ip");
 		if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP))
@@ -1094,6 +1313,37 @@
 			flags |= HAVE_DSTIP;
 			break;
 
+		case O_IP6_SRC:
+		case O_IP6_SRC_MASK:
+		case O_IP6_SRC_ME:
+			show_prerequisites(&flags, HAVE_PROTO6, 0);
+			if (!(flags & HAVE_SRCIP))
+				printf(" from");
+			if ((cmd->len & F_OR) && !or_block)
+				printf(" {");
+			print_ip6((ipfw_insn_ip6 *)cmd,
+				(flags & HAVE_OPTIONS) ? " src-ip6" : "");
+			flags |= HAVE_SRCIP | HAVE_PROTO;
+			break;
+
+		case O_IP6_DST:
+		case O_IP6_DST_MASK:
+		case O_IP6_DST_ME:
+			show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
+			if (!(flags & HAVE_DSTIP))
+				printf(" to");
+			if ((cmd->len & F_OR) && !or_block)
+				printf(" {");
+			print_ip6((ipfw_insn_ip6 *)cmd,
+				(flags & HAVE_OPTIONS) ? " dst-ip6" : "");
+			flags |= HAVE_DSTIP;
+			break;
+
+		case O_FLOW6ID:
+			print_flow6id( (ipfw_insn_u32 *) cmd );
+			flags |= HAVE_OPTIONS;
+			break;
+
 		case O_IP_DSTPORT:
 			show_prerequisites(&flags, HAVE_IP, 0);
 		case O_IP_SRCPORT:
@@ -1105,14 +1355,15 @@
 			break;
 
 		case O_PROTO: {
-			struct protoent *pe;
+			struct protoent *pe = NULL;
 
 			if ((cmd->len & F_OR) && !or_block)
 				printf(" {");
 			if (cmd->len & F_NOT)
 				printf(" not");
 			proto = cmd->arg1;
-			pe = getprotobynumber(cmd->arg1);
+			if (proto != 41)	/* XXX ipv6 is special */ 
+				pe = getprotobynumber(cmd->arg1);
 			if (flags & HAVE_OPTIONS)
 				printf(" proto");
 			if (pe)
@@ -1288,6 +1539,18 @@
 			    }
 				break;
 
+			case O_IP6:
+				printf(" ipv6");
+				break;
+
+			case O_ICMP6TYPE:
+				print_icmp6types((ipfw_insn_u32 *)cmd);
+				break;
+
+			case O_EXT_HDR:
+				print_ext6hdr( (ipfw_insn *) cmd );
+				break;
+
 			default:
 				printf(" [opcode %d len %d]",
 				    cmd->opcode, cmd->len);
@@ -1384,42 +1647,101 @@
 static void
 list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
 {
-	int l;
+	int l, index_print = 0;
+	char buff[255];
 
-	printf("    mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
-	    fs->flow_mask.proto,
-	    fs->flow_mask.src_ip, fs->flow_mask.src_port,
-	    fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
 	if (fs->rq_elements == 0)
 		return;
 
-	printf("BKT Prot ___Source IP/port____ "
-	    "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
 	if (do_sort != 0)
 		heapsort(q, fs->rq_elements, sizeof *q, sort_q);
-	for (l = 0; l < fs->rq_elements; l++) {
-		struct in_addr ina;
-		struct protoent *pe;
-
-		ina.s_addr = htonl(q[l].id.src_ip);
-		printf("%3d ", q[l].hash_slot);
-		pe = getprotobynumber(q[l].id.proto);
-		if (pe)
-			printf("%-4s ", pe->p_name);
-		else
-			printf("%4u ", q[l].id.proto);
-		printf("%15s/%-5d ",
-		    inet_ntoa(ina), q[l].id.src_port);
-		ina.s_addr = htonl(q[l].id.dst_ip);
-		printf("%15s/%-5d ",
-		    inet_ntoa(ina), q[l].id.dst_port);
-		printf("%4qu %8qu %2u %4u %3u\n",
-		    q[l].tot_pkts, q[l].tot_bytes,
-		    q[l].len, q[l].len_bytes, q[l].drops);
-		if (verbose)
-			printf("   S %20qd  F %20qd\n",
-			    q[l].S, q[l].F);
-	}
+
+	/*
+	 * Do IPv4 stuff
+	 */
+
+	for (l = 0; l < fs->rq_elements; l++) 
+		if (!IS_IP6_FLOW_ID(&(q[l].id))) {
+			struct in_addr ina;
+			struct protoent *pe;
+
+			if (!index_print) {
+				index_print = 1;
+				printf("\n        mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
+				    fs->flow_mask.proto,
+				    fs->flow_mask.src_ip, fs->flow_mask.src_port,
+				    fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
+
+				printf("    BKT Prot ___Source IP/port____ "
+					"____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
+			}
+			printf("    %3d ", q[l].hash_slot);
+			pe = getprotobynumber(q[l].id.proto);
+			if (pe)
+				printf("%-4s ", pe->p_name);
+			else
+				printf("%4u ", q[l].id.proto);
+			ina.s_addr = htonl(q[l].id.src_ip);
+			printf("%15s/%-5d ",
+			    inet_ntoa(ina), q[l].id.src_port);
+			ina.s_addr = htonl(q[l].id.dst_ip);
+			printf("%15s/%-5d ",
+			    inet_ntoa(ina), q[l].id.dst_port);
+			printf("%4qu %8qu %2u %4u %3u\n",
+		    		q[l].tot_pkts, q[l].tot_bytes,
+		    		q[l].len, q[l].len_bytes, q[l].drops);
+			if (verbose)
+				printf("   S %20qd  F %20qd\n",
+			    		q[l].S, q[l].F);
+		}
+
+	/*
+	 * Do IPv6 stuff
+	 */
+
+	index_print = 0;
+	for (l = 0; l < fs->rq_elements; l++) 
+		if (IS_IP6_FLOW_ID(&(q[l].id))) {
+			struct protoent *pe;
+
+			if (!index_print) {
+				index_print = 1;
+				printf("\n        mask: proto: 0x%02x, flow_id: 0x%08x,  ",
+		  			fs->flow_mask.proto, fs->flow_mask.flow_id6 );
+				inet_ntop(AF_INET6, &(fs->flow_mask.src_ip6),
+					buff, sizeof(buff) );
+				printf("%s/0x%04x -> ", buff, fs->flow_mask.src_port);
+				inet_ntop( AF_INET6, &(fs->flow_mask.dst_ip6),
+					buff, sizeof(buff) );
+				printf("%s/0x%04x\n", buff, fs->flow_mask.dst_port);
+
+				printf("    BKT ___Prot___ _flow-id_ "
+					"______________Source IPv6/port_______________ "
+					"_______________Dest. IPv6/port_______________ "
+					"Tot_pkt/bytes Pkt/Byte Drp\n");
+			}
+			printf("    %3d ", q[l].hash_slot);
+			pe = getprotobynumber(q[l].id.proto);
+			if (pe)
+				printf("%9s ", pe->p_name);
+			else
+				printf("%9u ", q[l].id.proto);
+			printf("%7d  %39s/%-5d ", q[l].id.flow_id6,
+				inet_ntop(AF_INET6, &(q[l].id.src_ip6),
+					buff, sizeof(buff)),
+				q[l].id.src_port);
+			printf(" %39s/%-5d ",
+				inet_ntop(AF_INET6, &(q[l].id.dst_ip6),
+					buff, sizeof(buff)),
+				q[l].id.dst_port);
+			printf(" %4qu %8qu %2u %4u %3u\n",
+		    		q[l].tot_pkts, q[l].tot_bytes,
+				q[l].len, q[l].len_bytes, q[l].drops);
+			if (verbose)
+				printf("   S %20qd  F %20qd\n",
+				q[l].S, q[l].F);
+		}
+	printf("\n");
 }
 
 static void
@@ -1802,7 +2124,7 @@
 	if (do_dynamic && ndyn) {
 		printf("## Dynamic rules:\n");
 		for (lac = ac, lav = av; lac != 0; lac--) {
-			rnum = strtoul(*lav++, &endptr, 10);
+			last = rnum = strtoul(*lav++, &endptr, 10);
 			if (*endptr == '-')
 				last = strtoul(endptr+1, &endptr, 10);
 			if (*endptr)
@@ -1854,17 +2176,22 @@
 "ACTION:	check-state | allow | count | deny | reject | skipto N |\n"
 "		{divert|tee} PORT | forward ADDR | pipe N | queue N\n"
 "ADDR:		[ MAC dst src ether_type ] \n"
-"		[ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
+"		[ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
+"		[ ipv6 from IP6ADDR [ PORT ] to IP6ADDR [ PORTLIST ] ]\n"
 "IPADDR:	[not] { any | me | ip/bits{x,y,z} | IPLIST }\n"
 "IPLIST:	{ ip | ip/bits | ip:mask }[,IPLIST]\n"
+"IP6ADDR:	[not] { any | me | me6 | ip6/bits | IP6LIST }\n"
+"IP6LIST:	{ ip6 | ip6/bits }[,IP6LIST]\n"
 "OPTION_LIST:	OPTION [OPTION_LIST]\n"
-"OPTION:	bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n"
+"OPTION:	bridged | {dst-ip|src-ip} IPADDR | {dst-port|src-port} LIST |\n"
 "	estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n"
 "	iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n"
 "	ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n"
 "	mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
 "	setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
-"	verrevpath\n"
+"	verrevpath | icmp6types LIST | ext6hdr LIST |\n"
+"        {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n"
+"        flow-id N[,N]\n"
 );
 exit(0);
 }
@@ -2058,6 +2385,227 @@
     cmd->o.len |= len+1;
 }
 
+/* XXX more ipv6 stuff */
+/* Try to find ipv6 address by hostname */
+static int
+lookup_host6 (char *host, struct in6_addr *ip6addr)
+{
+	struct hostent *he;
+
+	if (!inet_pton(AF_INET6, host, ip6addr)) {
+		if ((he = gethostbyname2(host, AF_INET6)) == NULL)
+			return(-1);
+		memcpy( ip6addr, he->h_addr_list[0], sizeof( struct in6_addr));
+	}
+	return(0);
+}
+
+/* n2mask sets n bits of the mask */
+
+static void
+n2mask(struct in6_addr *mask, int n)
+{
+	static int minimask[9] = {
+	    0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
+	};
+	u_char  *p;
+	int     i;
+
+	memset(mask, 0, sizeof(struct in6_addr));
+	p = (u_char *) mask;
+	for (i = 0; i < 16; i++, p++, n -= 8) {
+		if (n >= 8) {
+			*p = 0xff;
+			continue;
+		}
+		*p = minimask[n];
+		break;
+	}
+	return;
+}
+    
+/*
+ * fills the addr and mask fields in the instruction as appropriate from av.
+ * Update length as appropriate.
+ * The following formats are allowed:
+ *     any     matches any IP6. Actually returns an empty instruction.
+ *     me      returns O_IP6_*_ME
+ *
+ *     03f1::234:123:0342                single IP6 addres
+ *     03f1::234:123:0342/24            address/mask
+ *     03f1::234:123:0342/24,03f1::234:123:0343/               List of address
+ *
+ * Set of address (as in ipv6) not supported because ipv6 address
+ * are typically random past the initial prefix.
+ * Return 1 on success, 0 on failure.
+ */
+
+static int
+fill_ip6(ipfw_insn_ip6 *cmd, char *av)
+{
+	int len = 0;
+	struct in6_addr *d = &(cmd->addr6);
+	/* Needed for multiple address.
+	 * Note d[1] points to struct in6_add r mask6 of cmd
+	 */
+
+	cmd->o.len &= ~F_LEN_MASK;      /* zero len */
+
+	if (!strncmp(av, "any", strlen(av)))
+		return 1;
+
+
+	if (!strncmp(av, "me", strlen(av))) {	/* Set the data for "me" opt*/
+		cmd->o.len |= F_INSN_SIZE(ipfw_insn);
+		return 1;
+	}
+	if (!strncmp(av, "me6", strlen(av))) {	/* Set the data for "me" opt*/
+		cmd->o.len |= F_INSN_SIZE(ipfw_insn);
+		return 1;
+	}
+
+	av = strdup(av);
+	while (av) {
+		/*
+		 * After the address we can have '/' indicating a mask,
+		 * or ',' indicating another address follows.
+		 */
+
+		char *p;
+		int masklen;
+		char md = '\0';
+
+		if ((p = strpbrk( av, "/,")) ) {
+			md = *p;	/* save the separator */
+			*p = '\0';	/* terminate address string */
+			p++;		/* and skip past it */
+		}
+		/* now p points to NULL, mask or next entry */
+
+		/* lookup stores address in *d as a side effect */
+		if (lookup_host6(av, d) != 0) {
+			/* failed. Free memory and go */
+			errx(EX_DATAERR, "bad address \"%s\"", av);
+		}
+		/* next, look at the mask, if any */
+		masklen = (md == '/') ? atoi(p) : 128;
+		if (masklen > 128 || masklen < 0)
+			errx(EX_DATAERR, "bad width \"%s\''", p);
+		else
+			n2mask( &d[1], masklen);
+
+		APPLY_MASK( d, &d[1])	/* mask base address with mask */
+
+		/* find next separator */
+
+		if (md == '/') {	/* find separator past the mask */
+			p = strpbrk(p, ",");
+			if (p)
+				p++;
+		}
+		av = p;
+
+		/* Check this entry */
+		if (masklen == 0) {
+		    /*
+		     * 'any' turns the entire list into a NOP.
+		     * 'not any' never matches, so it is removed from the
+		     * list unless it is the only item, in which case we
+		     * report an error.
+		     */
+		    if (cmd->o.len & F_NOT) { /* "not any" never matches */
+			if (av == NULL && len == 0) /* only this entry */
+				errx(EX_DATAERR, "not any never matches");
+		    }
+		    /* else do nothing and skip this entry */
+		    continue;
+		}
+
+		/*
+		 * A single IP can be stored alone
+		 */
+		if (masklen == 128 && av == NULL && len == 0) {
+		    len = F_INSN_SIZE(struct in6_addr);
+		    break;
+		}
+
+		/* Update length and pointer to arguments */
+		len += F_INSN_SIZE(struct in6_addr)*2;
+		d += 2;
+	} /* end while */
+
+	/* Total lenght of the command, remember that 1 is the size of the base command */
+	cmd->o.len |= len+1;
+	free(av);
+	return 1;
+}
+
+/*
+ * fills command for ipv6 flow-id filtering
+ * note that the 20 bit flow number is stored in a array of u_int32_t
+ * it's supported lists of flow-id, so in the o.arg1 we store how many
+ * additional flow-id we want to filter, the basic is 1
+ */
+void
+fill_flow6( ipfw_insn_u32 *cmd, char *av )
+{
+	u_int32_t type;         /* Current flow number */
+	u_int16_t nflow = 0;    /* Current flow index */
+	char *s = av;
+	cmd->d[0] = 0;          /* Initializing the base number*/
+
+	while (s) {
+	    	av = strsep( &s, ",") ;
+		type = strtoul(av, &av, 0);
+		if (*av != ',' && *av != '\0')
+			errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
+		if (type > 0xfffff)
+			errx(EX_DATAERR, "flow number out of range %s", av);
+		cmd->d[nflow] |= type;
+		nflow++;
+	}
+	if( nflow > 0 ) {
+		cmd->o.opcode = O_FLOW6ID;
+		cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow;
+		cmd->o.arg1 = nflow;
+	}
+	else {
+		errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
+	}
+}
+
+static ipfw_insn *
+add_srcip6(ipfw_insn *cmd, char *av)
+{
+	fill_ip6( (ipfw_insn_ip6 *) cmd, av);
+	if (F_LEN(cmd) == 0)	/* any */
+		;
+	if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn))	/* "me" */
+		cmd->opcode = O_IP6_SRC_ME;
+	else if (F_LEN(cmd) == (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn)))
+		/* single IP, no mask*/
+		cmd->opcode = O_IP6_SRC;
+	else						/* addr/mask opt */
+		cmd->opcode = O_IP6_SRC_MASK;
+	return cmd;
+}
+
+static ipfw_insn *
+add_dstip6(ipfw_insn *cmd, char *av)
+{
+	fill_ip6((ipfw_insn_ip6 *)cmd, av);
+	if (F_LEN(cmd) == 0)	/* any */
+		;
+	if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn))	/* "me" */
+		cmd->opcode = O_IP6_DST_ME;
+	else if (F_LEN(cmd) == (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn)))
+		/* single IP, no mask*/
+		cmd->opcode = O_IP6_DST;
+	else						/* addr/mask opt */
+		cmd->opcode = O_IP6_DST_MASK;
+	return cmd;
+}
+/* end ipv6 stuff */
 
 /*
  * helper function to process a set of flags and set bits in the
@@ -2181,7 +2729,6 @@
 	struct dn_pipe p;
 	int i;
 	char *end;
-	uint32_t a;
 	void *par = NULL;
 
 	memset(&p, 0, sizeof p);
@@ -2243,16 +2790,15 @@
 			 */
 			par = NULL;
 
-			p.fs.flow_mask.dst_ip = 0;
-			p.fs.flow_mask.src_ip = 0;
-			p.fs.flow_mask.dst_port = 0;
-			p.fs.flow_mask.src_port = 0;
-			p.fs.flow_mask.proto = 0;
+			bzero(&p.fs.flow_mask, sizeof(p.fs.flow_mask));
 			end = NULL;
 
 			while (ac >= 1) {
 			    uint32_t *p32 = NULL;
 			    uint16_t *p16 = NULL;
+			    uint32_t *p20 = NULL;
+			    struct in6_addr *pa6 = NULL;
+			    uint32_t a;		/* the mask */
 
 			    tok = match_token(dummynet_params, *av);
 			    ac--; av++;
@@ -2266,6 +2812,9 @@
 				    p.fs.flow_mask.dst_port = ~0;
 				    p.fs.flow_mask.src_port = ~0;
 				    p.fs.flow_mask.proto = ~0;
+				    n2mask( &(p.fs.flow_mask.dst_ip6), 128);
+				    n2mask( &(p.fs.flow_mask.src_ip6), 128);
+				    p.fs.flow_mask.flow_id6 = ~0;
 				    p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
 				    goto end_mask;
 
@@ -2277,6 +2826,18 @@
 				    p32 = &p.fs.flow_mask.src_ip;
 				    break;
 
+			    case TOK_DSTIP6:
+				    pa6 =  &(p.fs.flow_mask.dst_ip6);
+				    break;
+
+			    case TOK_SRCIP6:
+				    pa6 = &(p.fs.flow_mask.src_ip6);
+				    break;
+
+			    case TOK_FLOWID:
+				    p20 = &p.fs.flow_mask.flow_id6;
+				    break;
+
 			    case TOK_DSTPORT:
 				    p16 = &p.fs.flow_mask.dst_port;
 				    break;
@@ -2294,22 +2855,35 @@
 			    }
 			    if (ac < 1)
 				    errx(EX_USAGE, "mask: value missing");
-			    if (*av[0] == '/') {
+			    if (*av[0] == '/') { /* mask len */
 				    a = strtoul(av[0]+1, &end, 0);
-				    a = (a == 32) ? ~0 : (1 << a) - 1;
-			    } else
+				    /* convert to a mask for non IPv6 */
+				    if (pa6 == NULL)
+					    a = (a == 32) ? ~0 : (1 << a) - 1;
+			    } else	/* explicit mask (non IPv6) */
 				    a = strtoul(av[0], &end, 0);
 			    if (p32 != NULL)
 				    *p32 = a;
 			    else if (p16 != NULL) {
-				    if (a > 65535)
+				    if (a > 0xffff)
 					    errx(EX_DATAERR,
-						"mask: must be 16 bit");
+						"port mask must be 16 bit");
 				    *p16 = (uint16_t)a;
+			    } else if (p20 != NULL) {
+				    if (a > 0xfffff)
+					errx(EX_DATAERR,
+					    "flow_id mask must be 20 bit");
+				    *p20 = (uint32_t)a;
+			    } else if (pa6 != NULL) {
+				    if (a < 0 || a > 128)
+					errx(EX_DATAERR,
+					    "in6addr invalid mask len" );
+				    else
+					n2mask(pa6, a);
 			    } else {
-				    if (a > 255)
+				    if (a > 0xff)
 					    errx(EX_DATAERR,
-						"mask: must be 8 bit");
+						"proto mask must be 8 bit");
 				    p.fs.flow_mask.proto = (uint8_t)a;
 			    }
 			    if (a != 0)
@@ -2629,21 +3203,27 @@
 }
 
 static ipfw_insn *
-add_proto(ipfw_insn *cmd, char *av)
+add_proto(ipfw_insn *cmd, char *av, u_char *proto)
 {
 	struct protoent *pe;
-	u_char proto = 0;
+        *proto = IPPROTO_IP;
 
 	if (!strncmp(av, "all", strlen(av)))
 		; /* same as "ip" */
-	else if ((proto = atoi(av)) > 0)
+	else if ((*proto = atoi(av)) > 0)
 		; /* all done! */
 	else if ((pe = getprotobyname(av)) != NULL)
-		proto = pe->p_proto;
+		*proto = pe->p_proto;
+	else if(!strncmp(av, "ipv6", strlen(av)) ||
+	        !strncmp(av, "ip6", strlen(av)) )
+		{
+		  *proto = IPPROTO_IPV6;
+		  return cmd;	/* special case for ipv6 */
+		}
 	else
 		return NULL;
-	if (proto != IPPROTO_IP)
-		fill_cmd(cmd, O_PROTO, 0, proto);
+	if (*proto != IPPROTO_IP && *proto != IPPROTO_IPV6)
+		fill_cmd(cmd, O_PROTO, 0, *proto);
 	return cmd;
 }
 
@@ -2690,6 +3270,38 @@
 	return NULL;
 }
 
+static ipfw_insn *
+add_src(ipfw_insn *cmd, char *av, u_char proto)
+{
+	struct in6_addr a;
+        if( proto == IPPROTO_IPV6  || strcmp( av, "me6") == 0 || inet_pton(AF_INET6, av, &a ))
+	  return add_srcip6(cmd, av);
+
+	if (proto == IPPROTO_IP || strcmp( av, "me") == 0 || !inet_pton(AF_INET6, av, &a ) ) 
+	  return add_srcip(cmd, av);
+
+	if( !strcmp( av, "any") )
+	  return cmd; 
+
+	return NULL;  /* bad address */
+}
+
+static ipfw_insn *
+add_dst(ipfw_insn *cmd, char *av, u_char proto)
+{
+	struct in6_addr a;
+        if( proto == IPPROTO_IPV6  || strcmp( av, "me6") == 0 || inet_pton(AF_INET6, av, &a ))
+	  return add_dstip6(cmd, av);
+
+	if (proto == IPPROTO_IP || strcmp( av, "me") == 0 || !inet_pton(AF_INET6, av, &a ) ) 
+	  return add_dstip(cmd, av);
+
+	if( !strcmp( av, "any") )
+	  return cmd; 
+
+	return NULL;  /* bad address */
+}
+
 /*
  * Parse arguments and assemble the microinstructions which make up a rule.
  * Rules are added into the 'rulebuf' and then copied in the correct order
@@ -2713,7 +3325,7 @@
 	 */
 	static uint32_t rulebuf[255], actbuf[255], cmdbuf[255];
 
-	ipfw_insn *src, *dst, *cmd, *action, *prev=NULL;
+	ipfw_insn *src, *dst, *cmd, *action, *prev=NULL, *retval=NULL;
 	ipfw_insn *first_cmd;	/* first match pattern */
 
 	struct ip_fw *rule;
@@ -2985,11 +3597,10 @@
     OR_START(get_proto);
 	NOT_BLOCK;
 	NEED1("missing protocol");
-	if (add_proto(cmd, *av)) {
+	if ( add_proto(cmd, *av, &proto) ) {
 		av++; ac--;
-		if (F_LEN(cmd) == 0)	/* plain IP */
-			proto = 0;
-		else {
+		if (F_LEN(cmd) != 0)	/* plain IP */
+		{
 			proto = cmd->arg1;
 			prev = cmd;
 			cmd = next_cmd(cmd);
@@ -3000,7 +3611,7 @@
 		goto read_options;
     OR_BLOCK(get_proto);
 
-	/*
+        /*
 	 * "from", mandatory
 	 */
 	if (!ac || strncmp(*av, "from", strlen(*av)))
@@ -3013,13 +3624,17 @@
     OR_START(source_ip);
 	NOT_BLOCK;	/* optional "not" */
 	NEED1("missing source address");
-	if (add_srcip(cmd, *av)) {
+	retval = add_src( cmd, *av, proto );
+		
+	if( retval ){
 		ac--; av++;
 		if (F_LEN(cmd) != 0) {	/* ! any */
 			prev = cmd;
 			cmd = next_cmd(cmd);
 		}
-	}
+	} else 
+		errx(EX_USAGE, "bad source address %s", *av);
+	        
     OR_BLOCK(source_ip);
 
 	/*
@@ -3048,13 +3663,17 @@
     OR_START(dest_ip);
 	NOT_BLOCK;	/* optional "not" */
 	NEED1("missing dst address");
-	if (add_dstip(cmd, *av)) {
+	retval = NULL;
+	retval = add_dst(cmd, *av, proto);
+
+	if( retval ){
 		ac--; av++;
 		if (F_LEN(cmd) != 0) {	/* ! any */
 			prev = cmd;
 			cmd = next_cmd(cmd);
 		}
-	}
+	} else
+		errx( EX_USAGE, "bad destination address %s", *av);
     OR_BLOCK(dest_ip);
 
 	/*
@@ -3160,6 +3779,12 @@
 			av++; ac--;
 			break;
 
+		case TOK_ICMP6TYPES:
+			NEED1("icmptypes requires list of types");
+			fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av);
+			av++; ac--;
+			break;
+
 		case TOK_IPTTL:
 			NEED1("ipttl requires TTL");
 			if (strpbrk(*av, "-,")) {
@@ -3336,8 +3961,9 @@
 
 		case TOK_PROTO:
 			NEED1("missing protocol");
-			if (add_proto(cmd, *av)) {
-				proto = cmd->arg1;
+			if ( add_proto(cmd, *av, &proto)) {
+				if ( proto == IPPROTO_IPV6 )
+			    	    fill_cmd(cmd, O_IP6, 0, 0);    
 				ac--; av++;
 			} else
 				errx(EX_DATAERR, "invalid protocol ``%s''",
@@ -3358,6 +3984,20 @@
 			}
 			break;
 
+		case TOK_SRCIP6:
+			NEED1("missing source IP6");
+			if (add_srcip6(cmd, *av)) {
+				ac--; av++;
+			}
+			break;
+
+		case TOK_DSTIP6:
+			NEED1("missing destination IP6");
+			if (add_dstip6(cmd, *av)) {
+				ac--; av++;
+			}
+			break;
+
 		case TOK_SRCPORT:
 			NEED1("missing source port");
 			if (!strncmp(*av, "any", strlen(*av)) ||
@@ -3404,6 +4044,23 @@
 			fill_comment(cmd, ac, av);
 			av += ac;
 			ac = 0;
+			break;
+
+		case TOK_IPV6:
+			fill_cmd(cmd, O_IP6, 0, 0);
+			ac--; av++;
+			break;
+			
+		case TOK_EXT6HDR:
+			fill_ext6hdr( cmd, *av );
+			ac--; av++;
+			break;
+
+		case TOK_FLOWID:
+			if (proto != IPPROTO_IPV6 ) 
+				errx( EX_USAGE, "flow-id filter is active only for ipv6 protocol\n");
+			fill_flow6( (ipfw_insn_u32 *) cmd, *av );
+	     		ac--;av++;
 			break;
 
 		default:
--- ./originali/raw_ip.c	Wed Jan 14 10:41:40 2004
+++ ./sys/netinet/raw_ip.c	Tue Mar 23 15:15:54 2004
@@ -35,6 +35,7 @@
  */
 
 #include "opt_inet6.h"
+#include "opt_ipfw.h"
 #include "opt_ipsec.h"
 #include "opt_random_ip_id.h"
 
--- ./originali/udp_usrreq.c	Wed Jan 14 10:42:52 2004
+++ ./sys/netinet/udp_usrreq.c	Tue Mar 23 15:15:54 2004
@@ -393,6 +393,13 @@
 		goto bad;
 #endif /*FAST_IPSEC*/
 
+#if 1	/* SRCSINK
+	 * If bit 15 if inp_inc.inc_pad is set, behave as a sink
+	 * and discard packet.
+	 */
+	if (inp->inp_inc.inc_pad & 0x8000)
+		goto bad; /* not really bad, just discard it */
+#endif	/* SRCSINK */
 	/*
 	 * Construct sockaddr format source address.
 	 * Stuff source address and datagram in user buffer.
@@ -765,6 +772,13 @@
 	((struct ip *)ui)->ip_tos = inp->inp_ip_tos;	/* XXX */
 	udpstat.udps_opackets++;
 
+#if 1	/* SRCSINK
+	 * If bits 0-14 of inp_inc.inc_pad are set, use that as
+	 * a replica count and pass them in the upper 16 bits of ipflags.
+	 */
+	if (inp->inp_inc.inc_pad & 0x7fff)
+		ipflags |= (inp->inp_inc.inc_pad & 0x7fff) << 16;
+#endif	/* SRCSINK */
 	error = ip_output(m, inp->inp_options, &inp->inp_route, ipflags,
 	    inp->inp_moptions, inp);
 
home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?HV2U9T$474E23C8CE7B556828F1BE7687979F9C>