teach npf ipv6-icmp trunk
authorspz <spz@NetBSD.org>
Thu, 19 Jul 2012 21:52:29 +0000
branchtrunk
changeset 212130 ee9299c49da5
parent 212129 0195fd2b01c5
child 212131 c8929f583f54
teach npf ipv6-icmp reviewed by rmind@
sys/net/npf/npf.h
sys/net/npf/npf_alg_icmp.c
sys/net/npf/npf_impl.h
sys/net/npf/npf_inet.c
sys/net/npf/npf_instr.c
sys/net/npf/npf_ncode.h
sys/net/npf/npf_processor.c
sys/net/npf/npf_session.c
usr.sbin/npf/npfctl/npf_build.c
usr.sbin/npf/npfctl/npf_data.c
usr.sbin/npf/npfctl/npf_disassemble.c
usr.sbin/npf/npfctl/npf_ncgen.c
usr.sbin/npf/npfctl/npf_parse.y
usr.sbin/npf/npfctl/npf_scan.l
usr.sbin/npf/npfctl/npf_var.h
usr.sbin/npf/npfctl/npfctl.h
--- a/sys/net/npf/npf.h	Thu Jul 19 21:08:42 2012 +0000
+++ b/sys/net/npf/npf.h	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.h,v 1.19 2012/07/15 00:23:00 rmind Exp $	*/
+/*	$NetBSD: npf.h,v 1.20 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -74,6 +74,7 @@
 #include <netinet/tcp.h>
 #include <netinet/udp.h>
 #include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
 
 #define	NPC_IP4		0x01	/* Indicates fetched IPv4 header. */
 #define	NPC_IP6		0x02	/* Indicates IPv6 header. */
@@ -104,9 +105,10 @@
 	} npc_ip;
 	/* TCP, UDP, ICMP. */
 	union {
-		struct tcphdr	tcp;
-		struct udphdr	udp;
-		struct icmp	icmp;
+		struct tcphdr		tcp;
+		struct udphdr		udp;
+		struct icmp		icmp;
+		struct icmp6_hdr	icmp6;
 	} npc_l4;
 } npf_cache_t;
 
--- a/sys/net/npf/npf_alg_icmp.c	Thu Jul 19 21:08:42 2012 +0000
+++ b/sys/net/npf/npf_alg_icmp.c	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_alg_icmp.c,v 1.10 2012/07/15 00:23:00 rmind Exp $	*/
+/*	$NetBSD: npf_alg_icmp.c,v 1.11 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.10 2012/07/15 00:23:00 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.11 2012/07/19 21:52:29 spz Exp $");
 
 #include <sys/param.h>
 #include <sys/module.h>
@@ -46,6 +46,7 @@
 #include <netinet/tcp.h>
 #include <netinet/udp.h>
 #include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
 #include <net/pfil.h>
 
 #include "npf_impl.h"
@@ -156,54 +157,102 @@
 static bool
 npf_icmp_uniqid(const int type, npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
 {
-	struct icmp *ic;
-	u_int offby;
+	struct icmp      *ic;
+	struct icmp6_hdr *ic6;
+	u_int            offby;
 
-	/* Per RFC 792. */
-	switch (type) {
-	case ICMP_UNREACH:
-	case ICMP_SOURCEQUENCH:
-	case ICMP_REDIRECT:
-	case ICMP_TIMXCEED:
-	case ICMP_PARAMPROB:
-		/* Should contain original IP header. */
-		offby = offsetof(struct icmp, icmp_ip);
-		if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) {
-			return false;
-		}
-		/* Fetch into the cache. */
-		if (!npf_fetch_ip(npc, nbuf, n_ptr)) {
-			return false;
+	if (npf_iscached(npc, NPC_IP4)) {
+		/* Per RFC 792. */
+		switch (type) {
+		case ICMP_UNREACH:
+		case ICMP_SOURCEQUENCH:
+		case ICMP_REDIRECT:
+		case ICMP_TIMXCEED:
+		case ICMP_PARAMPROB:
+			/* Should contain original IP header. */
+			offby = offsetof(struct icmp, icmp_ip);
+			if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) {
+				return false;
+			}
+			/* Fetch into the cache. */
+			if (!npf_fetch_ip(npc, nbuf, n_ptr)) {
+				return false;
+			}
+			switch (npf_cache_ipproto(npc)) {
+			case IPPROTO_TCP:
+				return npf_fetch_tcp(npc, nbuf, n_ptr);
+			case IPPROTO_UDP:
+				return npf_fetch_udp(npc, nbuf, n_ptr);
+			default:
+				return false;
+			}
+			return true;
+
+		case ICMP_ECHOREPLY:
+		case ICMP_ECHO:
+		case ICMP_TSTAMP:
+		case ICMP_TSTAMPREPLY:
+		case ICMP_IREQ:
+		case ICMP_IREQREPLY:
+			/* Should contain ICMP query ID. */
+			ic = &npc->npc_l4.icmp;
+			offby = offsetof(struct icmp, icmp_id);
+			if (nbuf_advfetch(&nbuf, &n_ptr, offby,
+			    sizeof(uint16_t), &ic->icmp_id)) {
+				return false;
+			}
+			npc->npc_info |= NPC_ICMP_ID;
+			return true;
+		default:
+			break;
 		}
-		switch (npf_cache_ipproto(npc)) {
-		case IPPROTO_TCP:
-			return npf_fetch_tcp(npc, nbuf, n_ptr);
-		case IPPROTO_UDP:
-			return npf_fetch_udp(npc, nbuf, n_ptr);
-		default:
-			return false;
-		}
-		return true;
+		/* No unique IDs. */
+		return false;
+	}
+	if (npf_iscached(npc, NPC_IP6)) {
+		switch (type) {
+		/* Per RFC 4443. */
+		case ICMP6_DST_UNREACH:
+		case ICMP6_PACKET_TOO_BIG:
+		case ICMP6_TIME_EXCEEDED:
+		case ICMP6_PARAM_PROB:
+			/* Should contain original IP header. */
+			offby = sizeof(struct icmp6_hdr);
+			if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) {
+				return false;
+			}
+			/* Fetch into the cache. */
+			if (!npf_fetch_ip(npc, nbuf, n_ptr)) {
+				return false;
+			}
+			switch (npf_cache_ipproto(npc)) {
+			case IPPROTO_TCP:
+				return npf_fetch_tcp(npc, nbuf, n_ptr);
+			case IPPROTO_UDP:
+				return npf_fetch_udp(npc, nbuf, n_ptr);
+			default:
+				return false;
+			}
+			return true;
 
-	case ICMP_ECHOREPLY:
-	case ICMP_ECHO:
-	case ICMP_TSTAMP:
-	case ICMP_TSTAMPREPLY:
-	case ICMP_IREQ:
-	case ICMP_IREQREPLY:
-		/* Should contain ICMP query ID. */
-		ic = &npc->npc_l4.icmp;
-		offby = offsetof(struct icmp, icmp_id);
-		if (nbuf_advfetch(&nbuf, &n_ptr, offby,
-		    sizeof(uint16_t), &ic->icmp_id)) {
-			return false;
+		case ICMP6_ECHO_REQUEST:
+		case ICMP6_ECHO_REPLY:
+			/* Should contain ICMP query ID. */
+			ic6 = &npc->npc_l4.icmp6;
+			offby = offsetof(struct icmp6_hdr, icmp6_id);
+			if (nbuf_advfetch(&nbuf, &n_ptr, offby,
+			    sizeof(uint16_t), &ic6->icmp6_id)) {
+				return false;
+			}
+			npc->npc_info |= NPC_ICMP_ID;
+			return true;
+		default:
+			break;
 		}
-		npc->npc_info |= NPC_ICMP_ID;
-		return true;
-	default:
-		break;
+		/* No unique IDs. */
+		return false;
 	}
-	/* No unique IDs. */
+	/* Whatever protocol that may have been ... */
 	return false;
 }
 
--- a/sys/net/npf/npf_impl.h	Thu Jul 19 21:08:42 2012 +0000
+++ b/sys/net/npf/npf_impl.h	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_impl.h,v 1.18 2012/07/15 00:23:00 rmind Exp $	*/
+/*	$NetBSD: npf_impl.h,v 1.19 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -208,6 +208,7 @@
 int		npf_match_udp_ports(npf_cache_t *, nbuf_t *, void *,
 		    const int, const uint32_t);
 int		npf_match_icmp4(npf_cache_t *, nbuf_t *, void *, uint32_t);
+int		npf_match_icmp6(npf_cache_t *, nbuf_t *, void *, uint32_t);
 int		npf_match_tcpfl(npf_cache_t *, nbuf_t *, void *, uint32_t);
 
 /* Tableset interface. */
--- a/sys/net/npf/npf_inet.c	Thu Jul 19 21:08:42 2012 +0000
+++ b/sys/net/npf/npf_inet.c	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_inet.c,v 1.14 2012/07/15 00:23:00 rmind Exp $	*/
+/*	$NetBSD: npf_inet.c,v 1.15 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.14 2012/07/15 00:23:00 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.15 2012/07/19 21:52:29 spz Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -463,14 +463,18 @@
 	if (!npf_iscached(npc, NPC_IP46) && !npf_fetch_ip(npc, nbuf, n_ptr)) {
 		return false;
 	}
-	if (npf_cache_ipproto(npc) != IPPROTO_ICMP) {
+	if (npf_cache_ipproto(npc) != IPPROTO_ICMP &&
+	    npf_cache_ipproto(npc) != IPPROTO_ICMPV6) {
 		return false;
 	}
 	ic = &npc->npc_l4.icmp;
 	hlen = npf_cache_hlen(npc);
 
 	/* Fetch basic ICMP header, up to the "data" point. */
-	iclen = offsetof(struct icmp, icmp_data);
+	CTASSERT(offsetof(struct icmp, icmp_void) ==
+	         offsetof(struct icmp6_hdr, icmp6_data32));
+
+	iclen = offsetof(struct icmp, icmp_void);
 	if (nbuf_advfetch(&nbuf, &n_ptr, hlen, iclen, ic)) {
 		return false;
 	}
@@ -503,6 +507,7 @@
 		(void)npf_fetch_udp(npc, nbuf, n_ptr);
 		break;
 	case IPPROTO_ICMP:
+	case IPPROTO_ICMPV6:
 		(void)npf_fetch_icmp(npc, nbuf, n_ptr);
 		break;
 	}
--- a/sys/net/npf/npf_instr.c	Thu Jul 19 21:08:42 2012 +0000
+++ b/sys/net/npf/npf_instr.c	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_instr.c,v 1.13 2012/07/15 00:23:00 rmind Exp $	*/
+/*	$NetBSD: npf_instr.c,v 1.14 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_instr.c,v 1.13 2012/07/15 00:23:00 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_instr.c,v 1.14 2012/07/19 21:52:29 spz Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -237,6 +237,37 @@
 }
 
 /*
+ * npf_match_icmp6: match ICMPv6 packet.
+ */
+int
+npf_match_icmp6(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, uint32_t tc)
+{
+	struct icmp6_hdr *ic6 = &npc->npc_l4.icmp6;
+
+	if (!npf_iscached(npc, NPC_ICMP)) {
+		if (!npf_fetch_icmp(npc, nbuf, n_ptr)) {
+			return -1;
+		}
+		KASSERT(npf_iscached(npc, NPC_ICMP));
+	}
+
+	/* Match code/type, if required. */
+	if ((1 << 31) & tc) {
+		const uint8_t type = (tc >> 8) & 0xff;
+		if (type != ic6->icmp6_type) {
+			return -1;
+		}
+	}
+	if ((1 << 30) & tc) {
+		const uint8_t code = tc & 0xff;
+		if (code != ic6->icmp6_code) {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
  * npf_match_tcpfl: match TCP flags.
  */
 int
--- a/sys/net/npf/npf_ncode.h	Thu Jul 19 21:08:42 2012 +0000
+++ b/sys/net/npf/npf_ncode.h	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ncode.h,v 1.9 2012/07/01 23:21:06 rmind Exp $	*/
+/*	$NetBSD: npf_ncode.h,v 1.10 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
@@ -118,6 +118,7 @@
 #define	NPF_OPCODE_TABLE		0x91
 #define	NPF_OPCODE_ICMP4		0x92
 #define	NPF_OPCODE_IP6MASK		0x93
+#define	NPF_OPCODE_ICMP6		0x94
 
 #define	NPF_OPCODE_TCP_PORTS		0xa0
 #define	NPF_OPCODE_UDP_PORTS		0xa1
@@ -139,7 +140,7 @@
 # define	NPF_OPERAND_SUBNET		9
 # define	NPF_OPERAND_LENGTH		10
 # define	NPF_OPERAND_TABLE_ID		11
-# define	NPF_OPERAND_ICMP4_TYPE_CODE	12
+# define	NPF_OPERAND_ICMP_TYPE_CODE	12
 # define	NPF_OPERAND_TCP_FLAGS_MASK	13
 # define	NPF_OPERAND_PORT_RANGE		14
 # define	NPF_OPERAND_PROTO		15
@@ -330,7 +331,13 @@
 	[NPF_OPCODE_ICMP4] = {
 		.name = "icmp4",
 		.op = {
-			[0] = NPF_OPERAND_ICMP4_TYPE_CODE,
+			[0] = NPF_OPERAND_ICMP_TYPE_CODE,
+		},
+	},
+	[NPF_OPCODE_ICMP6] = {
+		.name = "icmp6",
+		.op = {
+			[0] = NPF_OPERAND_ICMP_TYPE_CODE,
 		},
 	},
 	[NPF_OPCODE_IP6MASK] = {
--- a/sys/net/npf/npf_processor.c	Thu Jul 19 21:08:42 2012 +0000
+++ b/sys/net/npf/npf_processor.c	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_processor.c,v 1.11 2012/07/01 23:21:06 rmind Exp $	*/
+/*	$NetBSD: npf_processor.c,v 1.12 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
@@ -50,7 +50,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_processor.c,v 1.11 2012/07/01 23:21:06 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_processor.c,v 1.12 2012/07/19 21:52:29 spz Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -316,6 +316,11 @@
 		i_ptr = nc_fetch_word(i_ptr, &n);
 		cmpval = npf_match_icmp4(npc, nbuf, n_ptr, n);
 		break;
+	case NPF_OPCODE_ICMP6:
+		/* ICMP type/code. */
+		i_ptr = nc_fetch_word(i_ptr, &n);
+		cmpval = npf_match_icmp6(npc, nbuf, n_ptr, n);
+		break;
 	case NPF_OPCODE_PROTO:
 		i_ptr = nc_fetch_word(i_ptr, &n);
 		cmpval = npf_match_proto(npc, nbuf, n_ptr, n);
@@ -480,6 +485,7 @@
 		error = nc_ptr_check(&iptr, nc, sz, 1, NULL, 0);
 		break;
 	case NPF_OPCODE_ICMP4:
+	case NPF_OPCODE_ICMP6:
 		error = nc_ptr_check(&iptr, nc, sz, 1, NULL, 0);
 		break;
 	case NPF_OPCODE_PROTO:
--- a/sys/net/npf/npf_session.c	Thu Jul 19 21:08:42 2012 +0000
+++ b/sys/net/npf/npf_session.c	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_session.c,v 1.15 2012/07/15 00:23:00 rmind Exp $	*/
+/*	$NetBSD: npf_session.c,v 1.16 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2010-2012 The NetBSD Foundation, Inc.
@@ -80,7 +80,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.15 2012/07/15 00:23:00 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.16 2012/07/19 21:52:29 spz Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -495,7 +495,15 @@
 			senkey.se_dst_id = ic->icmp_id;
 			break;
 		}
-		/* FALLTHROUGH */
+		return NULL;
+	case IPPROTO_ICMPV6:
+		if (npf_iscached(key, NPC_ICMP_ID)) {
+			const struct icmp6_hdr *ic6 = &key->npc_l4.icmp6;
+			senkey.se_src_id = ic6->icmp6_id;
+			senkey.se_dst_id = ic6->icmp6_id;
+			break;
+		}
+		return NULL;
 	default:
 		/* Unsupported protocol. */
 		return NULL;
@@ -636,7 +644,18 @@
 			fw->se_dst_id = ic->icmp_id;
 			break;
 		}
-		/* FALLTHROUGH */
+		ok = false;
+		goto out;
+	case IPPROTO_ICMPV6:
+		if (npf_iscached(npc, NPC_ICMP_ID)) {
+			/* ICMP query ID. */
+			const struct icmp6_hdr *ic6 = &npc->npc_l4.icmp6;
+			fw->se_src_id = ic6->icmp6_id;
+			fw->se_dst_id = ic6->icmp6_id;
+			break;
+		}
+		ok = false;
+		goto out;
 	default:
 		/* Unsupported. */
 		ok = false;
--- a/usr.sbin/npf/npfctl/npf_build.c	Thu Jul 19 21:08:42 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_build.c	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_build.c,v 1.11 2012/07/15 00:22:58 rmind Exp $	*/
+/*	$NetBSD: npf_build.c,v 1.12 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_build.c,v 1.11 2012/07/15 00:22:58 rmind Exp $");
+__RCSID("$NetBSD: npf_build.c,v 1.12 2012/07/19 21:52:29 spz Exp $");
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
@@ -246,6 +246,21 @@
 		npfctl_gennc_icmp(nc, *icmp_type, *icmp_code);
 		nop = false;
 		break;
+	case IPPROTO_ICMPV6:
+		/*
+		 * Build ICMP block.
+		 */
+		if (!nop) {
+			goto invop;
+		}
+		assert(npfvar_get_count(popts) == 2);
+
+		int *icmp6_type, *icmp6_code;
+		icmp6_type = npfvar_get_data(popts, NPFVAR_ICMP6, 0);
+		icmp6_code = npfvar_get_data(popts, NPFVAR_ICMP6, 1);
+		npfctl_gennc_icmp6(nc, *icmp6_type, *icmp6_code);
+		nop = false;
+		break;
 	case -1:
 		pflag = NC_MATCH_TCP | NC_MATCH_UDP;
 		nop = false;
--- a/usr.sbin/npf/npfctl/npf_data.c	Thu Jul 19 21:08:42 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_data.c	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_data.c,v 1.15 2012/07/15 00:22:59 rmind Exp $	*/
+/*	$NetBSD: npf_data.c,v 1.16 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_data.c,v 1.15 2012/07/15 00:22:59 rmind Exp $");
+__RCSID("$NetBSD: npf_data.c,v 1.16 2012/07/19 21:52:29 spz Exp $");
 
 #include <sys/types.h>
 #include <sys/null.h>
@@ -41,6 +41,8 @@
 #include <netinet/ip.h>
 #define ICMP_STRINGS
 #include <netinet/ip_icmp.h>
+#define ICMP6_STRINGS
+#include <netinet/icmp6.h>
 #include <netinet/tcp.h>
 #include <net/if.h>
 
@@ -440,71 +442,142 @@
 }
 
 uint8_t
-npfctl_icmptype(const char *type)
+npfctl_icmptype(int proto, const char *type)
 {
-	for (uint8_t ul = 0; icmp_type[ul]; ul++)
-		if (strcmp(icmp_type[ul], type) == 0)
-			return ul;
+	uint8_t ul;
+
+	switch (proto) {
+	case IPPROTO_ICMP:
+		for (ul = 0; icmp_type[ul]; ul++)
+			if (strcmp(icmp_type[ul], type) == 0)
+				return ul;
+		break;
+	case IPPROTO_ICMPV6:
+		for (ul = 0; icmp6_type_err[ul]; ul++)
+			if (strcmp(icmp6_type_err[ul], type) == 0)
+				return ul;
+		for (ul = 0; icmp6_type_info[ul]; ul++)
+			if (strcmp(icmp6_type_info[ul], type) == 0)
+				return (ul+128);
+		break;
+	default:
+		assert(false);
+	}
+
+	yyerror("unknown icmp-type %s", type);
 	return ~0;
 }
 
 uint8_t
-npfctl_icmpcode(uint8_t type, const char *code)
+npfctl_icmpcode(int proto, uint8_t type, const char *code)
 {
 	const char **arr;
 
-	switch (type) {
-	case ICMP_ECHOREPLY:
-	case ICMP_SOURCEQUENCH:
-	case ICMP_ALTHOSTADDR:
-	case ICMP_ECHO:
-	case ICMP_ROUTERSOLICIT:
-	case ICMP_TSTAMP:
-	case ICMP_TSTAMPREPLY:
-	case ICMP_IREQ:
-	case ICMP_IREQREPLY:
-	case ICMP_MASKREQ:
-	case ICMP_MASKREPLY:
-		arr = icmp_code_none;
+	switch (proto) {
+	case IPPROTO_ICMP:
+		switch (type) {
+		case ICMP_ECHOREPLY:
+		case ICMP_SOURCEQUENCH:
+		case ICMP_ALTHOSTADDR:
+		case ICMP_ECHO:
+		case ICMP_ROUTERSOLICIT:
+		case ICMP_TSTAMP:
+		case ICMP_TSTAMPREPLY:
+		case ICMP_IREQ:
+		case ICMP_IREQREPLY:
+		case ICMP_MASKREQ:
+		case ICMP_MASKREPLY:
+			arr = icmp_code_none;
+			break;
+		case ICMP_ROUTERADVERT:
+			arr = icmp_code_routeradvert;
+			break;
+		case ICMP_UNREACH:
+			arr = icmp_code_unreach;
+			break;
+		case ICMP_REDIRECT:
+			arr = icmp_code_redirect;
+			break;
+		case ICMP_TIMXCEED:
+			arr = icmp_code_timxceed;
+			break;
+		case ICMP_PARAMPROB:
+			arr = icmp_code_paramprob;
+			break;
+		case ICMP_PHOTURIS:
+			arr = icmp_code_photuris;
+			break;
+		default:
+			yyerror("unknown icmp-type %d while parsing code %s",
+				type, code);
+			return ~0;
+		}
 		break;
-	case ICMP_ROUTERADVERT:
-		arr = icmp_code_routeradvert;
-		break;
-	case ICMP_UNREACH:
-		arr = icmp_code_unreach;
-		break;
-	case ICMP_REDIRECT:
-		arr = icmp_code_redirect;
-		break;
-	case ICMP_TIMXCEED:
-		arr = icmp_code_timxceed;
-		break;
-	case ICMP_PARAMPROB:
-		arr = icmp_code_paramprob;
-		break;
-	case ICMP_PHOTURIS:
-		arr = icmp_code_photuris;
+	case IPPROTO_ICMPV6:
+		switch (type) {
+		case ICMP6_DST_UNREACH:
+			arr = icmp6_code_unreach;
+			break;
+		case ICMP6_TIME_EXCEEDED:
+			arr = icmp6_code_timxceed;
+			break;
+		case ICMP6_PARAM_PROB:
+			arr = icmp6_code_paramprob;
+			break;
+		case ICMP6_PACKET_TOO_BIG:
+		/* code-less info ICMPs */
+		case ICMP6_ECHO_REQUEST:
+		case ICMP6_ECHO_REPLY:
+		case MLD_LISTENER_QUERY:
+		case MLD_LISTENER_REPORT:
+		case MLD_LISTENER_DONE:
+		case ND_ROUTER_SOLICIT:
+		case ND_ROUTER_ADVERT:
+		case ND_NEIGHBOR_SOLICIT:
+		case ND_NEIGHBOR_ADVERT:
+		case ND_REDIRECT:
+			arr = icmp6_code_none;
+			break;
+		/* XXX TODO: info ICMPs with code values */
+		default:
+			yyerror("unknown icmp-type %d while parsing code %s",
+				type, code);
+			return ~0;
+		}
 		break;
 	default:
-		return ~0;
+		assert(false);
 	}
 
 	for (uint8_t ul = 0; arr[ul]; ul++) {
 		if (strcmp(arr[ul], code) == 0)
 			return ul;
 	}
+	yyerror("unknown code %s for icmp-type %d", code, type);
 	return ~0;
 }
 
 npfvar_t *
-npfctl_parse_icmp(int type, int code)
+npfctl_parse_icmp(int proto, int type, int code)
 {
-	npfvar_t *vp = npfvar_create(".icmp");
+	npfvar_t *vp=npfvar_create(".icmp");
+	int      varnum;
 
-	if (!npfvar_add_element(vp, NPFVAR_ICMP, &type, sizeof(type)))
+	switch (proto) {
+	case IPPROTO_ICMP:
+		varnum = NPFVAR_ICMP;
+		break;
+	case IPPROTO_ICMPV6:
+		varnum = NPFVAR_ICMP6;
+		break;
+	default:
+		assert(false);
+	}
+
+	if (!npfvar_add_element(vp, varnum, &type, sizeof(type)))
 		goto out;
 
-	if (!npfvar_add_element(vp, NPFVAR_ICMP, &code, sizeof(code)))
+	if (!npfvar_add_element(vp, varnum, &code, sizeof(code)))
 		goto out;
 
 	return vp;
@@ -512,3 +585,4 @@
 	npfvar_destroy(vp);
 	return NULL;
 }
+
--- a/usr.sbin/npf/npfctl/npf_disassemble.c	Thu Jul 19 21:08:42 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_disassemble.c	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_disassemble.c,v 1.7 2012/07/15 00:22:59 rmind Exp $	*/
+/*	$NetBSD: npf_disassemble.c,v 1.8 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_disassemble.c,v 1.7 2012/07/15 00:22:59 rmind Exp $");
+__RCSID("$NetBSD: npf_disassemble.c,v 1.8 2012/07/19 21:52:29 spz Exp $");
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -232,7 +232,7 @@
 		snprintf(buf, bufsiz, "id=%d", op);
 		break;
 
-	case NPF_OPERAND_ICMP4_TYPE_CODE: {
+	case NPF_OPERAND_ICMP_TYPE_CODE: {
 		uint8_t type = (op & 31) ? op >> 8 : 0;
 		uint8_t code = (op & 30) ? op & 0xff : 0;
 
--- a/usr.sbin/npf/npfctl/npf_ncgen.c	Thu Jul 19 21:08:42 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_ncgen.c	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ncgen.c,v 1.12 2012/07/15 00:22:59 rmind Exp $	*/
+/*	$NetBSD: npf_ncgen.c,v 1.13 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_ncgen.c,v 1.12 2012/07/15 00:22:59 rmind Exp $");
+__RCSID("$NetBSD: npf_ncgen.c,v 1.13 2012/07/19 21:52:29 spz Exp $");
 
 #include <stdlib.h>
 #include <stddef.h>
@@ -343,6 +343,26 @@
 }
 
 /*
+ * npfctl_gennc_icmp6: fragment to match ICMPV6 type and code.
+ */
+void
+npfctl_gennc_icmp6(nc_ctx_t *ctx, int type, int code)
+{
+	uint32_t *nc = npfctl_ncgen_getptr(ctx, 4 /* words */);
+
+	/* OP, code, type (2 words) */
+	*nc++ = NPF_OPCODE_ICMP6;
+	*nc++ = (type == -1 ? 0 : (1 << 31) | ((type & 0xff) << 8)) |
+		(code == -1 ? 0 : (1 << 30) | (code & 0xff));
+
+	/* Comparison block (2 words). */
+	npfctl_ncgen_addjmp(ctx, &nc);
+
+	/* + 4 words. */
+	npfctl_ncgen_putptr(ctx, nc);
+}
+
+/*
  * npfctl_gennc_tbl: fragment to match IPv4 source/destination address of
  * the packet against table specified by ID.
  */
--- a/usr.sbin/npf/npfctl/npf_parse.y	Thu Jul 19 21:08:42 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_parse.y	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_parse.y,v 1.10 2012/07/15 00:22:59 rmind Exp $	*/
+/*	$NetBSD: npf_parse.y,v 1.11 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -120,7 +120,8 @@
 %token			TO
 %token			TREE
 %token			TYPE
-%token			ICMP
+%token	<num>		ICMP
+%token	<num>		ICMP6
 
 %token	<num>		HEX
 %token	<str>		IDENTIFIER
@@ -471,6 +472,11 @@
 		$$.op_proto = IPPROTO_ICMP;
 		$$.op_opts = $3;
 	}
+	| PROTO ICMP6 icmp_type_and_code
+	{
+		$$.op_proto = IPPROTO_ICMPV6;
+		$$.op_opts = $3;
+	}
 	| PROTO some_name
 	{
 		$$.op_proto = npfctl_protono($2);
@@ -633,24 +639,24 @@
 icmp_type_and_code
 	: ICMPTYPE icmp_type
 	{
-		$$ = npfctl_parse_icmp($2, -1);
+		$$ = npfctl_parse_icmp($<num>0, $2, -1);
 	}
 	| ICMPTYPE icmp_type CODE NUM
 	{
-		$$ = npfctl_parse_icmp($2, $4);
+		$$ = npfctl_parse_icmp($<num>0, $2, $4);
 	}
 	| ICMPTYPE icmp_type CODE IDENTIFIER
 	{
-		$$ = npfctl_parse_icmp($2, npfctl_icmpcode($2, $4));
+		$$ = npfctl_parse_icmp($<num>0, $2, npfctl_icmpcode($<num>0, $2, $4));
 	}
 	| ICMPTYPE icmp_type CODE VAR_ID
 	{
 		char *s = npfvar_expand_string(npfvar_lookup($4));
-		$$ = npfctl_parse_icmp($2, npfctl_icmpcode($2, s));
+		$$ = npfctl_parse_icmp($<num>0, $2, npfctl_icmpcode($<num>0, $2, s));
 	}
 	|
 	{
-		$$ = npfctl_parse_icmp(-1, -1);
+		$$ = npfctl_parse_icmp($<num>0, -1, -1);
 	}
 	;
 
@@ -675,11 +681,11 @@
 
 icmp_type
 	: NUM		{ $$ = $1; }
-	| IDENTIFIER	{ $$ = npfctl_icmptype($1); }
+	| IDENTIFIER	{ $$ = npfctl_icmptype($<num>-1, $1); }
 	| VAR_ID
 	{
 		char *s = npfvar_expand_string(npfvar_lookup($1));
-		$$ = npfctl_icmptype(s);
+		$$ = npfctl_icmptype($<num>-1, s);
 	}
 	;
 
--- a/usr.sbin/npf/npfctl/npf_scan.l	Thu Jul 19 21:08:42 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_scan.l	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_scan.l,v 1.4 2012/07/01 23:21:07 rmind Exp $	*/
+/*	$NetBSD: npf_scan.l,v 1.5 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -85,7 +85,9 @@
 proto			return PROTO;
 family			return FAMILY;
 tcp			return TCP;
-icmp			return ICMP;
+icmp			{ yylval.num = IPPROTO_ICMP; return ICMP; }
+ipv6-icmp		{ yylval.num = IPPROTO_ICMPV6; return ICMP6; }
+\"ipv6-icmp\"		{ yylval.num = IPPROTO_ICMPV6; return ICMP6; }
 return-rst		return RETURNRST;
 return-icmp		return RETURNICMP;
 return			return RETURN;
--- a/usr.sbin/npf/npfctl/npf_var.h	Thu Jul 19 21:08:42 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_var.h	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_var.h,v 1.2 2012/02/26 21:50:05 christos Exp $	*/
+/*	$NetBSD: npf_var.h,v 1.3 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -48,11 +48,12 @@
 #define	NPFVAR_ICMP		8
 #define	NPFVAR_PROC_OP		9
 #define	NPFVAR_MODULE_ARG	10
+#define	NPFVAR_ICMP6		11
 
 #ifdef _NPFVAR_PRIVATE
 static const char *npfvar_types[ ] = {
 	"string", "identifier", "var_id", "num", "table", "fam", "port_range",
-	"tcpflag", "icmp", "proc_op", "module_arg"
+	"tcpflag", "icmp", "proc_op", "module_arg", "icmp6"
 };
 #endif
 
--- a/usr.sbin/npf/npfctl/npfctl.h	Thu Jul 19 21:08:42 2012 +0000
+++ b/usr.sbin/npf/npfctl/npfctl.h	Thu Jul 19 21:52:29 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npfctl.h,v 1.17 2012/07/15 00:22:59 rmind Exp $	*/
+/*	$NetBSD: npfctl.h,v 1.18 2012/07/19 21:52:29 spz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -99,13 +99,12 @@
 bool		npfctl_table_exists_p(const char *);
 int		npfctl_protono(const char *);
 in_port_t	npfctl_portno(const char *);
-uint8_t		npfctl_icmpcode(uint8_t, const char *);
-uint8_t		npfctl_icmptype(const char *);
+uint8_t		npfctl_icmpcode(int, uint8_t, const char *);
+uint8_t		npfctl_icmptype(int, const char *);
 unsigned long   npfctl_find_ifindex(const char *);
 npfvar_t *	npfctl_parse_tcpflag(const char *);
 npfvar_t *	npfctl_parse_table_id(const char *);
-npfvar_t * 	npfctl_parse_icmpcode(const char *);
-npfvar_t * 	npfctl_parse_icmp(int, int);
+npfvar_t * 	npfctl_parse_icmp(int, int, int);
 npfvar_t *	npfctl_parse_iface(const char *);
 npfvar_t *	npfctl_parse_port_range(in_port_t, in_port_t);
 npfvar_t *	npfctl_parse_port_range_variable(const char *);
@@ -125,6 +124,7 @@
 #define	NC_MATCH_TCP		0x04
 #define	NC_MATCH_UDP		0x08
 #define	NC_MATCH_ICMP		0x10
+#define	NC_MATCH_ICMP6		0x20
 
 nc_ctx_t *	npfctl_ncgen_create(void);
 void *		npfctl_ncgen_complete(nc_ctx_t *, size_t *);
@@ -139,6 +139,7 @@
 		    const npf_netmask_t);
 void		npfctl_gennc_ports(nc_ctx_t *, int, in_port_t, in_port_t);
 void		npfctl_gennc_icmp(nc_ctx_t *, int, int);
+void		npfctl_gennc_icmp6(nc_ctx_t *, int, int);
 void		npfctl_gennc_tbl(nc_ctx_t *, int, u_int);
 void		npfctl_gennc_tcpfl(nc_ctx_t *, uint8_t, uint8_t);
 void		npfctl_gennc_proto(nc_ctx_t *ctx, uint8_t, uint8_t);