Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 Dec 2004 11:36:50 +0100
From:      Vladimir Kotal <vlada@devnull.cz>
To:        freebsd-ipfw@freebsd.org
Subject:   Re: ipfw2 for IPV6
Message-ID:  <20041221103650.GC25908@otaku.xtrmntr.org>

next in thread | raw e-mail | index | archive | help

--7ZAtKRhVyVSsbBD2
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline


On Fri, Sep 03, 2004 at 02:51:37PM -0700, Brooks Davis wrote:
> 
> I've included a patch against current below.  Be aware that you must
> run with debug.mpsafenet=0 if you want to try IPv6 output rules.  The
> current code doesn't handle the case where the firewall changes the
> destination, but modulo bugs, we are probably at feature parity with
> ip6fw.

Hello,

I'm attaching another variation of Luigi's/Mariano's patch. This is patch
against 4.10-RELEASE and has following features/problems:

- packet matching works in both directions in the right constellation
- I've added logging code from ip6_fw.c
- sbin/ipfw2.c parsing code can cause incorrect functionality, even
  segfault in some cases (see included regress script)


v.

--7ZAtKRhVyVSsbBD2
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="ipfw2-ipv6-dummynet.patch"

diff -uNr --exclude=compile src.orig/sbin/ipfw/ipfw2.c src/sbin/ipfw/ipfw2.c
--- src.orig/sbin/ipfw/ipfw2.c	Sat Jan 31 20:16:46 2004
+++ src/sbin/ipfw/ipfw2.c	Tue Dec 21 11:18:27 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 */
@@ -244,6 +245,13 @@
 	TOK_DROPTAIL,
 	TOK_PROTO,
 	TOK_WEIGHT,
+
+	TOK_IPV6,
+	TOK_FLOWID,
+	TOK_ICMP6TYPES,
+	TOK_EXT6HDR,
+	TOK_DSTIP6,
+	TOK_SRCIP6,
 };
 
 struct _s_x dummynet_params[] = {
@@ -266,6 +274,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 */
 };
@@ -340,6 +355,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 */
@@ -827,6 +852,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 < IPFW2_ICMP6_MAXV; 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
@@ -845,6 +1061,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)
@@ -865,6 +1082,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))
@@ -1095,6 +1314,40 @@
 			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:
+#if 0
+			show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
+#endif
+			show_prerequisites(&flags, HAVE_PROTO6|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 | HAVE_PROTO;
+			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:
@@ -1106,13 +1359,14 @@
 			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;
+			if (proto != 41)	/* XXX ipv6 is special */ 
 			pe = getprotobynumber(cmd->arg1);
 			if (flags & HAVE_OPTIONS)
 				printf(" proto");
@@ -1289,6 +1543,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);
@@ -1342,11 +1608,20 @@
 	else
 		printf(" proto %u", d->id.proto);
 
+	if (!IS_IP6_FLOW_ID(&(d->id))) {
 	a.s_addr = htonl(d->id.src_ip);
 	printf(" %s %d", inet_ntoa(a), d->id.src_port);
-
 	a.s_addr = htonl(d->id.dst_ip);
 	printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port);
+	} else {
+		char buff[255];
+		inet_ntop(AF_INET6, &(d->id.src_ip6),
+					buff, sizeof(buff) );
+		printf(" %s %d", buff, d->id.src_port); 	
+		inet_ntop(AF_INET6, &(d->id.dst_ip6),
+					buff, sizeof(buff) );
+		printf(" <-> %s %d", buff, d->id.dst_port); 	
+	}
 	printf("\n");
 }
 
@@ -1385,30 +1660,41 @@
 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++) {
+
+	/*
+	 * 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;
 
-		ina.s_addr = htonl(q[l].id.src_ip);
-		printf("%3d ", q[l].hash_slot);
+			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);
@@ -1421,6 +1707,54 @@
 			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
@@ -1803,7 +2137,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)
@@ -1855,17 +2189,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);
 }
@@ -2059,6 +2398,226 @@
     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 */
+		;
+	else 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 */
+		;
+	else 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
@@ -2182,7 +2741,6 @@
 	struct dn_pipe p;
 	int i;
 	char *end;
-	uint32_t a;
 	void *par = NULL;
 
 	memset(&p, 0, sizeof p);
@@ -2244,16 +2802,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++;
@@ -2267,6 +2824,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;
 
@@ -2278,6 +2838,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;
@@ -2295,22 +2867,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);
+				    /* convert to a mask for non IPv6 */
+				    if (pa6 == NULL)
 				    a = (a == 32) ? ~0 : (1 << a) - 1;
-			    } else
+			    } 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)
@@ -2630,21 +3215,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;
 }
 
@@ -2691,6 +3282,36 @@
 	return NULL;
 }
 
+static ipfw_insn *
+add_src(ipfw_insn *cmd, char *av, u_char proto)
+{
+        if( proto == IPPROTO_IPV6  || strcmp( av, "me6") == 0 || (inet_addr( av ) == INADDR_NONE)) 
+	  return add_srcip6(cmd, av);
+
+	if (proto == IPPROTO_IP || strcmp( av, "me") == 0 || (inet_addr(av) != INADDR_NONE) ) 
+	  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)
+{
+        if( proto == IPPROTO_IPV6  || strcmp( av, "me6") == 0 || (inet_addr(av) == INADDR_NONE) )
+	  return add_dstip6(cmd, av);
+
+	if (proto == IPPROTO_IP || strcmp( av, "me") == 0 || (inet_addr(av) != INADDR_NONE) ) 
+	  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
@@ -2714,7 +3335,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;
@@ -2986,11 +3607,14 @@
     OR_START(get_proto);
 	NOT_BLOCK;
 	NEED1("missing protocol");
-	if (add_proto(cmd, *av)) {
+	if ( add_proto(cmd, *av, &proto) ) {
+#if 0
+		if ( proto == IPPROTO_IPV6 )
+		  fill_cmd(cmd, O_IP6, 0, 0);
+#endif
 		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);
@@ -3014,13 +3638,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);
 
 	/*
@@ -3049,13 +3677,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);
 
 	/*
@@ -3161,6 +3793,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, "-,")) {
@@ -3337,8 +3975,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''",
@@ -3359,6 +3998,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)) ||
@@ -3405,6 +4058,24 @@
 			fill_comment(cmd, ac, av);
 			av += ac;
 			ac = 0;
+			break;
+
+		case TOK_IPV6:
+			fill_cmd(cmd, O_IP6, 0, 0);
+			/* XXX causes segfault */
+			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:
diff -uNr --exclude=compile src.orig/sys/net/if_ethersubr.c src/sys/net/if_ethersubr.c
--- src.orig/sys/net/if_ethersubr.c	Wed Mar  3 13:35:16 2004
+++ src/sys/net/if_ethersubr.c	Wed Dec 15 10:28:33 2004
@@ -40,6 +40,7 @@
 #include "opt_ipx.h"
 #include "opt_bdg.h"
 #include "opt_netgraph.h"
+#include "opt_ipfw.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
diff -uNr --exclude=compile src.orig/sys/netinet/ip_dummynet.c src/sys/netinet/ip_dummynet.c
--- src.orig/sys/netinet/ip_dummynet.c	Tue Dec 30 13:28:09 2003
+++ src/sys/netinet/ip_dummynet.c	Wed Dec 15 10:04:37 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_timeout.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 */
+	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 ;
 
@@ -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 ;
diff -uNr --exclude=compile src.orig/sys/netinet/ip_dummynet.h src/sys/netinet/ip_dummynet.h
--- src.orig/sys/netinet/ip_dummynet.h	Tue May 13 11:31:06 2003
+++ src/sys/netinet/ip_dummynet.h	Wed Dec 15 10:04:37 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+):
diff -uNr --exclude=compile src.orig/sys/netinet/ip_fw2.c src/sys/netinet/ip_fw2.c
--- src.orig/sys/netinet/ip_fw2.c	Fri Apr  2 19:15:44 2004
+++ src/sys/netinet/ip_fw2.c	Mon Dec 20 15:53:16 2004
@@ -77,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 */
@@ -235,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)) );
 }
@@ -251,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
@@ -329,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);
 
@@ -447,6 +455,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...) */
 
@@ -463,7 +548,7 @@
 {
 	char *action;
 	int limit_reached = 0;
-	char action2[40], proto[48], fragment[28];
+	char action2[40], proto[102], fragment[28];
 
 	fragment[0] = '\0';
 	proto[0] = '\0';
@@ -547,9 +632,70 @@
 		}
 	}
 
-	if (hlen == 0) {	/* non-ip */
-		snprintf(SNPARGS(proto, 0), "MAC");
+	/* preserve hlen == 0 semantics */
+	if ((hlen == 0) && 
+		 mtod(m, struct ip *)->ip_v == 6) { /* IPv6 packet */
+	  int len;
+	  struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
+	  u_int8_t protonum = mtod(m, struct ip6_hdr *)->ip6_nxt;
+	  int off = sizeof(struct ip6_hdr);
+	  struct tcphdr *const tcp6 = (struct tcphdr *) ((caddr_t) ip6+ off);
+	  struct udphdr *const udp = (struct udphdr *) ((caddr_t) ip6+ off);
+	  struct icmp6_hdr *const icmp6 = (struct icmp6_hdr *) ((caddr_t) ip6+ off);
+
+#define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0
+
+	  switch (protonum) {
+	    case IPPROTO_TCP:
+		len = snprintf(SNPARGS(proto, 0), "TCP [%s]",
+		    ip6_sprintf(&ip6->ip6_src));
+		if (off > 0)
+			len += snprintf(SNPARGS(proto, len), ":%d ",
+			    ntohs(tcp6->th_sport));
+		else
+			len += snprintf(SNPARGS(proto, len), " ");
+		len += snprintf(SNPARGS(proto, len), "[%s]",
+		    ip6_sprintf(&ip6->ip6_dst));
+		if (off > 0)
+			snprintf(SNPARGS(proto, len), ":%d",
+			    ntohs(tcp6->th_dport));
+		break;
+	    case IPPROTO_UDP:
+		len = snprintf(SNPARGS(proto, 0), "UDP [%s]",
+		    ip6_sprintf(&ip6->ip6_src));
+		if (off > 0)
+			len += snprintf(SNPARGS(proto, len), ":%d ",
+			    ntohs(udp->uh_sport));
+		else
+		    len += snprintf(SNPARGS(proto, len), " ");
+		len += snprintf(SNPARGS(proto, len), "[%s]",
+		    ip6_sprintf(&ip6->ip6_dst));
+		if (off > 0)
+			snprintf(SNPARGS(proto, len), ":%d",
+			    ntohs(udp->uh_dport));
+		break;
+	    case IPPROTO_ICMPV6:
+		if (off > 0)
+			len = snprintf(SNPARGS(proto, 0), "IPV6-ICMP:%u.%u ",
+			    icmp6->icmp6_type, icmp6->icmp6_code);
+		else
+			len = snprintf(SNPARGS(proto, 0), "IPV6-ICMP ");
+		len += snprintf(SNPARGS(proto, len), "[%s]",
+		    ip6_sprintf(&ip6->ip6_src));
+		snprintf(SNPARGS(proto, len), " [%s]",
+		    ip6_sprintf(&ip6->ip6_dst));
+		break;
+	    default:
+		len = snprintf(SNPARGS(proto, 0), "P:%d [%s]", protonum,
+		    ip6_sprintf(&ip6->ip6_src));
+		snprintf(SNPARGS(proto, len), " [%s]",
+		    ip6_sprintf(&ip6->ip6_dst));
+		break;
+	  }
 	} else {
+	  if (hlen == 0)
+		snprintf(SNPARGS(proto, 0), "MAC");
+	  else {
 		struct ip *ip = mtod(m, struct ip *);
 		/* these three are all aliases to the same thing */
 		struct icmp *const icmp = L3HDR(struct icmp, ip);
@@ -621,6 +767,7 @@
 			     ntohs(ip->ip_id), ip_len - (ip->ip_hl << 2),
 			     offset << 3,
 			     (ip_off & IP_MF) ? "+" : "");
+	  }
 	}
 	if (oif || m->m_pkthdr.rcvif)
 		log(LOG_SECURITY | LOG_INFO,
@@ -651,7 +798,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;
 }
@@ -776,7 +925,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;
@@ -786,6 +935,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 &&
@@ -801,6 +971,7 @@
 				break;
 			}
 		}
+		}
 next:
 		prev = q;
 		q = q->next;
@@ -976,15 +1147,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;
@@ -1050,14 +1231,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 (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)
@@ -1297,12 +1485,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
@@ -1319,12 +1503,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;
@@ -1348,32 +1532,151 @@
 	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)
 	 */
+	int dyn_dir = MATCH_UNKNOWN;
+	ipfw_dyn_rule *q = NULL;
+
+	/*
+	 * 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.
+	 */
+	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;
-	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;
+	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;
+
+		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.
 	 */
-	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;
-	}
 
-	proto = args->f_id.proto = ip->ip_p;
+	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 */
@@ -1385,58 +1688,41 @@
 	}
 	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)
-
 	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);
+	}
+	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
@@ -1529,13 +1815,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;
@@ -1621,7 +1905,7 @@
 				break;
 
 			case O_FRAG:
-				match = (hlen > 0 && offset != 0);
+				match = offset != 0;
 				break;
 
 			case O_IN:	/* "out" is "not in" */
@@ -1706,7 +1990,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)
@@ -1726,15 +2010,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:
@@ -1748,9 +2042,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;
@@ -1765,49 +2059,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:
@@ -1822,8 +2114,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;
 
@@ -1838,6 +2133,62 @@
 				/* 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);
+				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
@@ -1900,7 +2251,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
@@ -1965,7 +2316,7 @@
 				 */
 				if (hlen > 0 &&
 				    (proto != IPPROTO_ICMP ||
-				     is_icmp_query(ip)) &&
+				     is_icmp_query(ICMP(ulp))) &&
 				    !(m->m_flags & (M_BCAST|M_MCAST)) &&
 				    !IN_MULTICAST(ntohl(dst_ip.s_addr))) {
 					send_reject(args, cmd->arg1,
@@ -2412,6 +2763,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;
@@ -2525,6 +2880,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);
@@ -2794,7 +3172,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",
diff -uNr --exclude=compile src.orig/sys/netinet/ip_fw2.h src/sys/netinet/ip_fw2.h
--- src.orig/sys/netinet/ip_fw2.h	Thu Jul 17 08:03:39 2003
+++ src/sys/netinet/ip_fw2.h	Wed Dec 15 10:05:00 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,			/* Ipv6 protocol presence */
+
 	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,31 @@
 	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 */
+#define IPFW2_ICMP6_MAXV 7	/* XXX This number is related to the netinet/icmp6.h
+				 *	define ICMP6_MAXTYPE
+				 *	as follws: n = ICMP6_MAXTYPE/32 + 1
+				 *	Actually the define is 203
+				 */
+typedef struct _ipfw_insn_icmp6 {
+	ipfw_insn o;
+	uint32_t d[IPFW2_ICMP6_MAXV];
+} ipfw_insn_icmp6;
+
 /*
  * Here we have the structure representing an ipfw rule.
  *
@@ -327,8 +374,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.
  */
@@ -384,6 +438,17 @@
 #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
  * efficient to pass variables around and extend the interface.
@@ -402,6 +467,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 */
 };
 
 /*
diff -uNr --exclude=compile src.orig/sys/netinet/ip_fw2.h.orig src/sys/netinet/ip_fw2.h.orig
--- src.orig/sys/netinet/ip_fw2.h.orig	Thu Jan  1 01:00:00 1970
+++ src/sys/netinet/ip_fw2.h.orig	Thu Jul 17 08:03:39 2003
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/netinet/ip_fw2.h,v 1.1.2.4 2003/07/17 06:03:39 luigi Exp $
+ */
+
+#ifndef _IPFW2_H
+#define _IPFW2_H
+
+/*
+ * The kernel representation of ipfw rules is made of a list of
+ * 'instructions' (for all practical purposes equivalent to BPF
+ * instructions), which specify which fields of the packet
+ * (or its metadata) should be analysed.
+ *
+ * Each instruction is stored in a structure which begins with
+ * "ipfw_insn", and can contain extra fields depending on the
+ * instruction type (listed below).
+ * Note that the code is written so that individual instructions
+ * have a size which is a multiple of 32 bits. This means that, if
+ * such structures contain pointers or other 64-bit entities,
+ * (there is just one instance now) they may end up unaligned on
+ * 64-bit architectures, so the must be handled with care.
+ *
+ * "enum ipfw_opcodes" are the opcodes supported. We can have up
+ * to 256 different opcodes.
+ */
+
+enum ipfw_opcodes {		/* arguments (4 byte each)	*/
+	O_NOP,
+
+	O_IP_SRC,		/* u32 = IP			*/
+	O_IP_SRC_MASK,		/* ip = IP/mask			*/
+	O_IP_SRC_ME,		/* none				*/
+	O_IP_SRC_SET,		/* u32=base, arg1=len, bitmap	*/
+
+	O_IP_DST,		/* u32 = IP			*/
+	O_IP_DST_MASK,		/* ip = IP/mask			*/
+	O_IP_DST_ME,		/* none				*/
+	O_IP_DST_SET,		/* u32=base, arg1=len, bitmap	*/
+
+	O_IP_SRCPORT,		/* (n)port list:mask 4 byte ea	*/
+	O_IP_DSTPORT,		/* (n)port list:mask 4 byte ea	*/
+	O_PROTO,		/* arg1=protocol		*/
+
+	O_MACADDR2,		/* 2 mac addr:mask		*/
+	O_MAC_TYPE,		/* same as srcport		*/
+
+	O_LAYER2,		/* none				*/
+	O_IN,			/* none				*/
+	O_FRAG,			/* none				*/
+
+	O_RECV,			/* none				*/
+	O_XMIT,			/* none				*/
+	O_VIA,			/* none				*/
+
+	O_IPOPT,		/* arg1 = 2*u8 bitmap		*/
+	O_IPLEN,		/* arg1 = len			*/
+	O_IPID,			/* arg1 = id			*/
+
+	O_IPTOS,		/* arg1 = id			*/
+	O_IPPRECEDENCE,		/* arg1 = precedence << 5	*/
+	O_IPTTL,		/* arg1 = TTL			*/
+
+	O_IPVER,		/* arg1 = version		*/
+	O_UID,			/* u32 = id			*/
+	O_GID,			/* u32 = id			*/
+	O_ESTAB,		/* none (tcp established)	*/
+	O_TCPFLAGS,		/* arg1 = 2*u8 bitmap		*/
+	O_TCPWIN,		/* arg1 = desired win		*/
+	O_TCPSEQ,		/* u32 = desired seq.		*/
+	O_TCPACK,		/* u32 = desired seq.		*/
+	O_ICMPTYPE,		/* u32 = icmp bitmap		*/
+	O_TCPOPTS,		/* arg1 = 2*u8 bitmap		*/
+
+	O_VERREVPATH,		/* none				*/
+
+	O_PROBE_STATE,		/* none				*/
+	O_KEEP_STATE,		/* none				*/
+	O_LIMIT,		/* ipfw_insn_limit		*/
+	O_LIMIT_PARENT,		/* dyn_type, not an opcode.	*/
+
+	/*
+	 * These are really 'actions'.
+	 */
+
+	O_LOG,			/* ipfw_insn_log		*/
+	O_PROB,			/* u32 = match probability	*/
+
+	O_CHECK_STATE,		/* none				*/
+	O_ACCEPT,		/* none				*/
+	O_DENY,			/* none 			*/
+	O_REJECT,		/* arg1=icmp arg (same as deny)	*/
+	O_COUNT,		/* none				*/
+	O_SKIPTO,		/* arg1=next rule number	*/
+	O_PIPE,			/* arg1=pipe number		*/
+	O_QUEUE,		/* arg1=queue number		*/
+	O_DIVERT,		/* arg1=port number		*/
+	O_TEE,			/* arg1=port number		*/
+	O_FORWARD_IP,		/* fwd sockaddr			*/
+	O_FORWARD_MAC,		/* fwd mac			*/
+
+	/*
+	 * More opcodes.
+	 */
+	O_IPSEC,		/* has ipsec history		*/
+
+	O_LAST_OPCODE		/* not an opcode!		*/
+};
+
+/*
+ * Template for instructions.
+ *
+ * ipfw_insn is used for all instructions which require no operands,
+ * a single 16-bit value (arg1), or a couple of 8-bit values.
+ *
+ * For other instructions which require different/larger arguments
+ * we have derived structures, ipfw_insn_*.
+ *
+ * The size of the instruction (in 32-bit words) is in the low
+ * 6 bits of "len". The 2 remaining bits are used to implement
+ * NOT and OR on individual instructions. Given a type, you can
+ * compute the length to be put in "len" using F_INSN_SIZE(t)
+ *
+ * F_NOT	negates the match result of the instruction.
+ *
+ * F_OR		is used to build or blocks. By default, instructions
+ *		are evaluated as part of a logical AND. An "or" block
+ *		{ X or Y or Z } contains F_OR set in all but the last
+ *		instruction of the block. A match will cause the code
+ *		to skip past the last instruction of the block.
+ *
+ * NOTA BENE: in a couple of places we assume that
+ *	sizeof(ipfw_insn) == sizeof(u_int32_t)
+ * this needs to be fixed.
+ *
+ */
+typedef struct	_ipfw_insn {	/* template for instructions */
+	enum ipfw_opcodes	opcode:8;
+	u_int8_t	len;	/* numer of 32-byte words */
+#define	F_NOT		0x80
+#define	F_OR		0x40
+#define	F_LEN_MASK	0x3f
+#define	F_LEN(cmd)	((cmd)->len & F_LEN_MASK)
+
+	u_int16_t	arg1;
+} ipfw_insn;
+
+/*
+ * The F_INSN_SIZE(type) computes the size, in 4-byte words, of
+ * a given type.
+ */
+#define	F_INSN_SIZE(t)	((sizeof (t))/sizeof(u_int32_t))
+
+/*
+ * This is used to store an array of 16-bit entries (ports etc.)
+ */
+typedef struct	_ipfw_insn_u16 {
+	ipfw_insn o;
+	u_int16_t ports[2];	/* there may be more */
+} ipfw_insn_u16;
+
+/*
+ * This is used to store an array of 32-bit entries
+ * (uid, single IPv4 addresses etc.)
+ */
+typedef struct	_ipfw_insn_u32 {
+	ipfw_insn o;
+	u_int32_t d[1];	/* one or more */
+} ipfw_insn_u32;
+
+/*
+ * This is used to store IP addr-mask pairs.
+ */
+typedef struct	_ipfw_insn_ip {
+	ipfw_insn o;
+	struct in_addr	addr;
+	struct in_addr	mask;
+} ipfw_insn_ip;
+
+/*
+ * This is used to forward to a given address (ip).
+ */
+typedef struct  _ipfw_insn_sa {
+	ipfw_insn o;
+	struct sockaddr_in sa;
+} ipfw_insn_sa;
+
+/*
+ * This is used for MAC addr-mask pairs.
+ */
+typedef struct	_ipfw_insn_mac {
+	ipfw_insn o;
+	u_char addr[12];	/* dst[6] + src[6] */
+	u_char mask[12];	/* dst[6] + src[6] */
+} ipfw_insn_mac;
+
+/*
+ * This is used for interface match rules (recv xx, xmit xx).
+ */
+typedef struct	_ipfw_insn_if {
+	ipfw_insn o;
+	union {
+		struct in_addr ip;
+		int32_t unit;
+	} p;
+	char name[IFNAMSIZ];
+} ipfw_insn_if;
+
+/*
+ * This is used for pipe and queue actions, which need to store
+ * a single pointer (which can have different size on different
+ * architectures.
+ * Note that, because of previous instructions, pipe_ptr might
+ * be unaligned in the overall structure, so it needs to be
+ * manipulated with care.
+ */
+typedef struct	_ipfw_insn_pipe {
+	ipfw_insn	o;
+	void		*pipe_ptr;	/* XXX */
+} ipfw_insn_pipe;
+
+/*
+ * This is used for limit rules.
+ */
+typedef struct	_ipfw_insn_limit {
+	ipfw_insn o;
+	u_int8_t _pad;
+	u_int8_t limit_mask;	/* combination of DYN_* below	*/
+#define	DYN_SRC_ADDR	0x1
+#define	DYN_SRC_PORT	0x2
+#define	DYN_DST_ADDR	0x4
+#define	DYN_DST_PORT	0x8
+
+	u_int16_t conn_limit;
+} ipfw_insn_limit;
+
+/*
+ * This is used for log instructions.
+ */
+typedef struct  _ipfw_insn_log {
+        ipfw_insn o;
+	u_int32_t max_log;	/* how many do we log -- 0 = all */
+	u_int32_t log_left;	/* how many left to log 	*/
+} ipfw_insn_log;
+
+/*
+ * Here we have the structure representing an ipfw rule.
+ *
+ * It starts with a general area (with link fields and counters)
+ * followed by an array of one or more instructions, which the code
+ * accesses as an array of 32-bit values.
+ *
+ * Given a rule pointer  r:
+ *
+ *  r->cmd		is the start of the first instruction.
+ *  ACTION_PTR(r)	is the start of the first action (things to do
+ *			once a rule matched).
+ *
+ * When assembling instruction, remember the following:
+ *
+ *  + if a rule has a "keep-state" (or "limit") option, then the
+ *	first instruction (at r->cmd) MUST BE an O_PROBE_STATE
+ *  + if a rule has a "log" option, then the first action
+ *	(at ACTION_PTR(r)) MUST be O_LOG
+ *
+ * NOTE: we use a simple linked list of rules because we never need
+ * 	to delete a rule without scanning the list. We do not use
+ *	queue(3) macros for portability and readability.
+ */
+
+struct ip_fw {
+	struct ip_fw	*next;		/* linked list of rules		*/
+	struct ip_fw	*next_rule;	/* ptr to next [skipto] rule	*/
+	/* 'next_rule' is used to pass up 'set_disable' status		*/
+
+	u_int16_t	act_ofs;	/* offset of action in 32-bit units */
+	u_int16_t	cmd_len;	/* # of 32-bit words in cmd	*/
+	u_int16_t	rulenum;	/* rule number			*/
+	u_int8_t	set;		/* rule set (0..31)		*/
+#define	RESVD_SET	31	/* set for default and persistent rules */
+	u_int8_t	_pad;		/* padding			*/
+
+	/* These fields are present in all rules.			*/
+	u_int64_t	pcnt;		/* Packet counter		*/
+	u_int64_t	bcnt;		/* Byte counter			*/
+	u_int32_t	timestamp;	/* tv_sec of last match		*/
+
+	ipfw_insn	cmd[1];		/* storage for commands		*/
+};
+
+#define ACTION_PTR(rule)				\
+	(ipfw_insn *)( (u_int32_t *)((rule)->cmd) + ((rule)->act_ofs) )
+
+#define RULESIZE(rule)  (sizeof(struct ip_fw) + \
+	((struct ip_fw *)(rule))->cmd_len * 4 - 4)
+
+/*
+ * This structure is used as a flow mask and a flow id for various
+ * parts of the code.
+ */
+struct ipfw_flow_id {
+	u_int32_t	dst_ip;
+	u_int32_t	src_ip;
+	u_int16_t	dst_port;
+	u_int16_t	src_port;
+	u_int8_t	proto;
+	u_int8_t	flags;	/* protocol-specific flags */
+};
+
+/*
+ * Dynamic ipfw rule.
+ */
+typedef struct _ipfw_dyn_rule ipfw_dyn_rule;
+
+struct _ipfw_dyn_rule {
+	ipfw_dyn_rule	*next;		/* linked list of rules.	*/
+	struct ip_fw *rule;		/* pointer to rule		*/
+	/* 'rule' is used to pass up the rule number (from the parent)	*/
+
+	ipfw_dyn_rule *parent;		/* pointer to parent rule	*/
+	u_int64_t	pcnt;		/* packet match counter		*/
+	u_int64_t	bcnt;		/* byte match counter		*/
+	struct ipfw_flow_id id;		/* (masked) flow id		*/
+	u_int32_t	expire;		/* expire time			*/
+	u_int32_t	bucket;		/* which bucket in hash table	*/
+	u_int32_t	state;		/* state of this rule (typically a
+					 * combination of TCP flags)
+					 */
+	u_int32_t	ack_fwd;	/* most recent ACKs in forward	*/
+	u_int32_t	ack_rev;	/* and reverse directions (used	*/
+					/* to generate keepalives)	*/
+	u_int16_t	dyn_type;	/* rule type			*/
+	u_int16_t	count;		/* refcount			*/
+};
+
+/*
+ * Definitions for IP option names.
+ */
+#define	IP_FW_IPOPT_LSRR	0x01
+#define	IP_FW_IPOPT_SSRR	0x02
+#define	IP_FW_IPOPT_RR		0x04
+#define	IP_FW_IPOPT_TS		0x08
+
+/*
+ * Definitions for TCP option names.
+ */
+#define	IP_FW_TCPOPT_MSS	0x01
+#define	IP_FW_TCPOPT_WINDOW	0x02
+#define	IP_FW_TCPOPT_SACK	0x04
+#define	IP_FW_TCPOPT_TS		0x08
+#define	IP_FW_TCPOPT_CC		0x10
+
+#define	ICMP_REJECT_RST		0x100	/* fake ICMP code (send a TCP RST) */
+
+/*
+ * Main firewall chains definitions and global var's definitions.
+ */
+#ifdef _KERNEL
+
+#define	IP_FW_PORT_DYNT_FLAG	0x10000
+#define	IP_FW_PORT_TEE_FLAG	0x20000
+#define	IP_FW_PORT_DENY_FLAG	0x40000
+
+/*
+ * Arguments for calling ipfw_chk() and dummynet_io(). We put them
+ * all into a structure because this way it is easier and more
+ * efficient to pass variables around and extend the interface.
+ */
+struct ip_fw_args {
+	struct mbuf	*m;		/* the mbuf chain		*/
+	struct ifnet	*oif;		/* output interface		*/
+	struct sockaddr_in *next_hop;	/* forward address		*/
+	struct ip_fw	*rule;		/* matching rule		*/
+	struct ether_header *eh;	/* for bridged packets		*/
+
+	struct route	*ro;		/* for dummynet			*/
+	struct sockaddr_in *dst;	/* for dummynet			*/
+	int flags;			/* for dummynet			*/
+
+	struct ipfw_flow_id f_id;	/* grabbed from IP header	*/
+	u_int16_t	divert_rule;	/* divert cookie		*/
+	u_int32_t	retval;
+};
+
+/*
+ * Function definitions.
+ */
+
+/* Firewall hooks */
+struct sockopt;
+struct dn_flow_set;
+
+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 */
diff -uNr --exclude=compile src.orig/sys/netinet/raw_ip.c src/sys/netinet/raw_ip.c
--- src.orig/sys/netinet/raw_ip.c	Tue Sep 16 07:43:56 2003
+++ src/sys/netinet/raw_ip.c	Wed Dec 15 10:29:39 2004
@@ -37,6 +37,7 @@
 #include "opt_inet6.h"
 #include "opt_ipsec.h"
 #include "opt_random_ip_id.h"
+#include "opt_ipfw.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
diff -uNr --exclude=compile src.orig/sys/netinet6/ip6_forward.c src/sys/netinet6/ip6_forward.c
--- src.orig/sys/netinet6/ip6_forward.c	Fri Jan 24 06:11:35 2003
+++ src/sys/netinet6/ip6_forward.c	Wed Dec 15 10:42:20 2004
@@ -34,6 +34,7 @@
 #include "opt_inet.h"
 #include "opt_inet6.h"
 #include "opt_ipsec.h"
+#include "opt_ipfw.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -457,6 +458,7 @@
 	/*
 	 * Check with the firewall...
 	 */
+#ifndef IPFW2
 	if (ip6_fw_enable && ip6_fw_chk_ptr) {
 		u_short port = 0;
 		/* If ipfw says divert, we have to just drop packet */
@@ -467,6 +469,7 @@
 		if (!m)
 			goto freecopy;
 	}
+#endif
 
 	/*
 	 * Fake scoped addresses. Note that even link-local source or
diff -uNr --exclude=compile src.orig/sys/netinet6/ip6_input.c src/sys/netinet6/ip6_input.c
--- src.orig/sys/netinet6/ip6_input.c	Fri Jan 24 06:11:35 2003
+++ src/sys/netinet6/ip6_input.c	Wed Dec 15 10:05:00 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.
diff -uNr --exclude=compile src.orig/sys/netinet6/ip6_output.c src/sys/netinet6/ip6_output.c
--- src.orig/sys/netinet6/ip6_output.c	Sun Mar 28 17:11:57 2004
+++ src/sys/netinet6/ip6_output.c	Wed Dec 15 10:05:00 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"
@@ -108,7 +108,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>
 
@@ -173,6 +179,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;
@@ -187,6 +196,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) {							\
@@ -765,6 +834,7 @@
 		}
 	}
 
+send_after_dummynet:
 	/*
 	 * Fill the outgoing inteface to tell the upper layer
 	 * to increment per-interface statistics.
@@ -836,6 +906,68 @@
 	/*
 	 * 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 */
@@ -849,7 +981,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.
@@ -1637,6 +1769,7 @@
 				break;
 #endif /* KAME IPSEC */
 
+#ifndef IPFW2
 			case IPV6_FW_ADD:
 			case IPV6_FW_DEL:
 			case IPV6_FW_FLUSH:
@@ -1657,7 +1790,7 @@
 				m = *mp;
 			    }
 				break;
-
+#endif /* !IPFW2 */
 			default:
 				error = ENOPROTOOPT;
 				break;
@@ -1797,6 +1930,7 @@
 			  }
 #endif /* KAME IPSEC */
 
+#ifndef IPFW2
 			case IPV6_FW_GET:
 			  {
 				struct mbuf *m;
@@ -1813,6 +1947,7 @@
 					m_freem(m);
 			  }
 				break;
+#endif /* !IPFW2 */
 
 			default:
 				error = ENOPROTOOPT;
@@ -2241,8 +2376,8 @@
 		 * If an interface address was specified, get a pointer
 		 * to its ifnet structure.
 		 */
-		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;
 		}
@@ -2253,7 +2388,7 @@
 		 */
 		if (IN6_IS_ADDR_MC_LINKLOCAL(&mreq->ipv6mr_multiaddr)) {
 			mreq->ipv6mr_multiaddr.s6_addr16[1]
-				= htons(mreq->ipv6mr_interface);
+				= htons(ifp->if_index);
 		}
 		/*
 		 * Find the membership in the membership list.

--7ZAtKRhVyVSsbBD2--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20041221103650.GC25908>