diff -ruNp linux-2.6.22.5/include/linux/snmp.h linux-2.6.22.5_ICMPMSG/include/linux/snmp.h
--- linux-2.6.22.5/include/linux/snmp.h	2007-08-22 16:23:54.000000000 -0700
+++ linux-2.6.22.5_ICMPMSG/include/linux/snmp.h	2007-08-23 15:32:29.000000000 -0700
@@ -82,6 +82,8 @@ enum
 	__ICMP_MIB_MAX
 };
 
+#define __ICMPMSG_MIB_MAX 512	/* Out+In for all 8-bit ICMP types */
+
 /* icmp6 mib definitions */
 /*
  * RFC 2466:  ICMPv6-MIB
diff -ruNp linux-2.6.22.5/include/net/icmp.h linux-2.6.22.5_ICMPMSG/include/net/icmp.h
--- linux-2.6.22.5/include/net/icmp.h	2007-08-22 16:23:54.000000000 -0700
+++ linux-2.6.22.5_ICMPMSG/include/net/icmp.h	2007-08-23 15:56:45.000000000 -0700
@@ -30,9 +30,16 @@ struct icmp_err {
 
 extern struct icmp_err icmp_err_convert[];
 DECLARE_SNMP_STAT(struct icmp_mib, icmp_statistics);
+DECLARE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics);
 #define ICMP_INC_STATS(field)		SNMP_INC_STATS(icmp_statistics, field)
 #define ICMP_INC_STATS_BH(field)	SNMP_INC_STATS_BH(icmp_statistics, field)
 #define ICMP_INC_STATS_USER(field) 	SNMP_INC_STATS_USER(icmp_statistics, field)
+#define ICMPMSGOUT_INC_STATS(field)	SNMP_INC_STATS(icmpmsg_statistics, field+256)
+#define ICMPMSGOUT_INC_STATS_BH(field)	SNMP_INC_STATS_BH(icmpmsg_statistics, field+256)
+#define ICMPMSGOUT_INC_STATS_USER(field) 	SNMP_INC_STATS_USER(icmpmsg_statistics, field+256)
+#define ICMPMSGIN_INC_STATS(field)	SNMP_INC_STATS(icmpmsg_statistics, field)
+#define ICMPMSGIN_INC_STATS_BH(field)	SNMP_INC_STATS_BH(icmpmsg_statistics, field)
+#define ICMPMSGIN_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmpmsg_statistics, field)
 
 struct dst_entry;
 struct net_proto_family;
@@ -42,6 +49,7 @@ extern void	icmp_send(struct sk_buff *sk
 extern int	icmp_rcv(struct sk_buff *skb);
 extern int	icmp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 extern void	icmp_init(struct net_proto_family *ops);
+extern void	icmp_out_count(unsigned char type);
 
 /* Move into dst.h ? */
 extern int 	xrlim_allow(struct dst_entry *dst, int timeout);
diff -ruNp linux-2.6.22.5/include/net/snmp.h linux-2.6.22.5_ICMPMSG/include/net/snmp.h
--- linux-2.6.22.5/include/net/snmp.h	2007-08-22 16:23:54.000000000 -0700
+++ linux-2.6.22.5_ICMPMSG/include/net/snmp.h	2007-08-23 14:42:50.000000000 -0700
@@ -82,6 +82,11 @@ struct icmp_mib {
 	unsigned long	mibs[ICMP_MIB_MAX];
 } __SNMP_MIB_ALIGN__;
 
+#define ICMPMSG_MIB_MAX	__ICMPMSG_MIB_MAX
+struct icmpmsg_mib {
+	unsigned long	mibs[ICMPMSG_MIB_MAX];
+} __SNMP_MIB_ALIGN__;
+
 /* ICMP6 (IPv6-ICMP) */
 #define ICMP6_MIB_MAX	__ICMP6_MIB_MAX
 struct icmpv6_mib {
diff -ruNp linux-2.6.22.5/net/ipv4/af_inet.c linux-2.6.22.5_ICMPMSG/net/ipv4/af_inet.c
--- linux-2.6.22.5/net/ipv4/af_inet.c	2007-08-22 16:23:54.000000000 -0700
+++ linux-2.6.22.5_ICMPMSG/net/ipv4/af_inet.c	2007-08-23 14:47:26.000000000 -0700
@@ -1296,6 +1296,10 @@ static int __init init_ipv4_mibs(void)
 			  sizeof(struct icmp_mib),
 			  __alignof__(struct icmp_mib)) < 0)
 		goto err_icmp_mib;
+	if (snmp_mib_init((void **)icmpmsg_statistics,
+			  sizeof(struct icmpmsg_mib),
+			  __alignof__(struct icmpmsg_mib)) < 0)
+		goto err_icmpmsg_mib;
 	if (snmp_mib_init((void **)tcp_statistics,
 			  sizeof(struct tcp_mib),
 			  __alignof__(struct tcp_mib)) < 0)
@@ -1318,6 +1322,8 @@ err_udplite_mib:
 err_udp_mib:
 	snmp_mib_free((void **)tcp_statistics);
 err_tcp_mib:
+	snmp_mib_free((void **)icmpmsg_statistics);
+err_icmpmsg_mib:
 	snmp_mib_free((void **)icmp_statistics);
 err_icmp_mib:
 	snmp_mib_free((void **)ip_statistics);
diff -ruNp linux-2.6.22.5/net/ipv4/icmp.c linux-2.6.22.5_ICMPMSG/net/ipv4/icmp.c
--- linux-2.6.22.5/net/ipv4/icmp.c	2007-08-22 16:23:54.000000000 -0700
+++ linux-2.6.22.5_ICMPMSG/net/ipv4/icmp.c	2007-08-23 15:57:07.000000000 -0700
@@ -115,6 +115,7 @@ struct icmp_bxm {
  *	Statistics
  */
 DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics) __read_mostly;
+DEFINE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics) __read_mostly;
 
 /* An array of errno for error messages from dest unreach. */
 /* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOST_UNREACH and SR_FAILED MUST be considered 'transient errs'. */
@@ -214,8 +215,6 @@ int sysctl_icmp_errors_use_inbound_ifadd
  */
 
 struct icmp_control {
-	int output_entry;	/* Field for increment on output */
-	int input_entry;	/* Field for increment on input */
 	void (*handler)(struct sk_buff *skb);
 	short   error;		/* This ICMP is classed as an error message */
 };
@@ -316,12 +315,10 @@ out:
 /*
  *	Maintain the counters used in the SNMP statistics for outgoing ICMP
  */
-static void icmp_out_count(int type)
+void icmp_out_count(unsigned char type)
 {
-	if (type <= NR_ICMP_TYPES) {
-		ICMP_INC_STATS(icmp_pointers[type].output_entry);
-		ICMP_INC_STATS(ICMP_MIB_OUTMSGS);
-	}
+	ICMPMSGOUT_INC_STATS(type);
+	ICMP_INC_STATS(ICMP_MIB_OUTMSGS);
 }
 
 /*
@@ -390,7 +387,6 @@ static void icmp_reply(struct icmp_bxm *
 		return;
 
 	icmp_param->data.icmph.checksum = 0;
-	icmp_out_count(icmp_param->data.icmph.type);
 
 	inet->tos = ip_hdr(skb)->tos;
 	daddr = ipc.addr = rt->rt_src;
@@ -952,6 +948,7 @@ int icmp_rcv(struct sk_buff *skb)
 
 	icmph = icmp_hdr(skb);
 
+	ICMPMSGIN_INC_STATS_BH(icmph->type);
 	/*
 	 *	18 is the highest 'known' ICMP type. Anything else is a mystery
 	 *
@@ -986,7 +983,6 @@ int icmp_rcv(struct sk_buff *skb)
 		}
 	}
 
-	ICMP_INC_STATS_BH(icmp_pointers[icmph->type].input_entry);
 	icmp_pointers[icmph->type].handler(skb);
 
 drop:
@@ -1002,109 +998,71 @@ error:
  */
 static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
 	[ICMP_ECHOREPLY] = {
-		.output_entry = ICMP_MIB_OUTECHOREPS,
-		.input_entry = ICMP_MIB_INECHOREPS,
 		.handler = icmp_discard,
 	},
 	[1] = {
-		.output_entry = ICMP_MIB_DUMMY,
-		.input_entry = ICMP_MIB_INERRORS,
 		.handler = icmp_discard,
 		.error = 1,
 	},
 	[2] = {
-		.output_entry = ICMP_MIB_DUMMY,
-		.input_entry = ICMP_MIB_INERRORS,
 		.handler = icmp_discard,
 		.error = 1,
 	},
 	[ICMP_DEST_UNREACH] = {
-		.output_entry = ICMP_MIB_OUTDESTUNREACHS,
-		.input_entry = ICMP_MIB_INDESTUNREACHS,
 		.handler = icmp_unreach,
 		.error = 1,
 	},
 	[ICMP_SOURCE_QUENCH] = {
-		.output_entry = ICMP_MIB_OUTSRCQUENCHS,
-		.input_entry = ICMP_MIB_INSRCQUENCHS,
 		.handler = icmp_unreach,
 		.error = 1,
 	},
 	[ICMP_REDIRECT] = {
-		.output_entry = ICMP_MIB_OUTREDIRECTS,
-		.input_entry = ICMP_MIB_INREDIRECTS,
 		.handler = icmp_redirect,
 		.error = 1,
 	},
 	[6] = {
-		.output_entry = ICMP_MIB_DUMMY,
-		.input_entry = ICMP_MIB_INERRORS,
 		.handler = icmp_discard,
 		.error = 1,
 	},
 	[7] = {
-		.output_entry = ICMP_MIB_DUMMY,
-		.input_entry = ICMP_MIB_INERRORS,
 		.handler = icmp_discard,
 		.error = 1,
 	},
 	[ICMP_ECHO] = {
-		.output_entry = ICMP_MIB_OUTECHOS,
-		.input_entry = ICMP_MIB_INECHOS,
 		.handler = icmp_echo,
 	},
 	[9] = {
-		.output_entry = ICMP_MIB_DUMMY,
-		.input_entry = ICMP_MIB_INERRORS,
 		.handler = icmp_discard,
 		.error = 1,
 	},
 	[10] = {
-		.output_entry = ICMP_MIB_DUMMY,
-		.input_entry = ICMP_MIB_INERRORS,
 		.handler = icmp_discard,
 		.error = 1,
 	},
 	[ICMP_TIME_EXCEEDED] = {
-		.output_entry = ICMP_MIB_OUTTIMEEXCDS,
-		.input_entry = ICMP_MIB_INTIMEEXCDS,
 		.handler = icmp_unreach,
 		.error = 1,
 	},
 	[ICMP_PARAMETERPROB] = {
-		.output_entry = ICMP_MIB_OUTPARMPROBS,
-		.input_entry = ICMP_MIB_INPARMPROBS,
 		.handler = icmp_unreach,
 		.error = 1,
 	},
 	[ICMP_TIMESTAMP] = {
-		.output_entry = ICMP_MIB_OUTTIMESTAMPS,
-		.input_entry = ICMP_MIB_INTIMESTAMPS,
 		.handler = icmp_timestamp,
 	},
 	[ICMP_TIMESTAMPREPLY] = {
-		.output_entry = ICMP_MIB_OUTTIMESTAMPREPS,
-		.input_entry = ICMP_MIB_INTIMESTAMPREPS,
 		.handler = icmp_discard,
 	},
 	[ICMP_INFO_REQUEST] = {
-		.output_entry = ICMP_MIB_DUMMY,
-		.input_entry = ICMP_MIB_DUMMY,
 		.handler = icmp_discard,
 	},
 	[ICMP_INFO_REPLY] = {
-		.output_entry = ICMP_MIB_DUMMY,
-		.input_entry = ICMP_MIB_DUMMY,
 		.handler = icmp_discard,
 	},
 	[ICMP_ADDRESS] = {
-		.output_entry = ICMP_MIB_OUTADDRMASKS,
-		.input_entry = ICMP_MIB_INADDRMASKS,
 		.handler = icmp_address,
 	},
 	[ICMP_ADDRESSREPLY] = {
-		.output_entry = ICMP_MIB_OUTADDRMASKREPS,
-		.input_entry = ICMP_MIB_INADDRMASKREPS,
 		.handler = icmp_address_reply,
 	},
 };
@@ -1146,4 +1104,5 @@ void __init icmp_init(struct net_proto_f
 EXPORT_SYMBOL(icmp_err_convert);
 EXPORT_SYMBOL(icmp_send);
 EXPORT_SYMBOL(icmp_statistics);
+EXPORT_SYMBOL(icmpmsg_statistics);
 EXPORT_SYMBOL(xrlim_allow);
diff -ruNp linux-2.6.22.5/net/ipv4/ip_output.c linux-2.6.22.5_ICMPMSG/net/ipv4/ip_output.c
--- linux-2.6.22.5/net/ipv4/ip_output.c	2007-08-22 16:23:54.000000000 -0700
+++ linux-2.6.22.5_ICMPMSG/net/ipv4/ip_output.c	2007-08-23 15:54:45.000000000 -0700
@@ -1258,6 +1258,10 @@ int ip_push_pending_frames(struct sock *
 	skb->priority = sk->sk_priority;
 	skb->dst = dst_clone(&rt->u.dst);
 
+	if (iph->protocol == IPPROTO_ICMP)
+		icmp_out_count(((struct icmphdr *)
+			skb_transport_header(skb))->type);
+
 	/* Netfilter gets whole the not fragmented skb. */
 	err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
 		      skb->dst->dev, dst_output);
diff -ruNp linux-2.6.22.5/net/ipv4/proc.c linux-2.6.22.5_ICMPMSG/net/ipv4/proc.c
--- linux-2.6.22.5/net/ipv4/proc.c	2007-08-22 16:23:54.000000000 -0700
+++ linux-2.6.22.5_ICMPMSG/net/ipv4/proc.c	2007-08-23 15:58:42.000000000 -0700
@@ -123,33 +123,30 @@ static const struct snmp_mib snmp4_ipext
 static const struct snmp_mib snmp4_icmp_list[] = {
 	SNMP_MIB_ITEM("InMsgs", ICMP_MIB_INMSGS),
 	SNMP_MIB_ITEM("InErrors", ICMP_MIB_INERRORS),
-	SNMP_MIB_ITEM("InDestUnreachs", ICMP_MIB_INDESTUNREACHS),
-	SNMP_MIB_ITEM("InTimeExcds", ICMP_MIB_INTIMEEXCDS),
-	SNMP_MIB_ITEM("InParmProbs", ICMP_MIB_INPARMPROBS),
-	SNMP_MIB_ITEM("InSrcQuenchs", ICMP_MIB_INSRCQUENCHS),
-	SNMP_MIB_ITEM("InRedirects", ICMP_MIB_INREDIRECTS),
-	SNMP_MIB_ITEM("InEchos", ICMP_MIB_INECHOS),
-	SNMP_MIB_ITEM("InEchoReps", ICMP_MIB_INECHOREPS),
-	SNMP_MIB_ITEM("InTimestamps", ICMP_MIB_INTIMESTAMPS),
-	SNMP_MIB_ITEM("InTimestampReps", ICMP_MIB_INTIMESTAMPREPS),
-	SNMP_MIB_ITEM("InAddrMasks", ICMP_MIB_INADDRMASKS),
-	SNMP_MIB_ITEM("InAddrMaskReps", ICMP_MIB_INADDRMASKREPS),
 	SNMP_MIB_ITEM("OutMsgs", ICMP_MIB_OUTMSGS),
 	SNMP_MIB_ITEM("OutErrors", ICMP_MIB_OUTERRORS),
-	SNMP_MIB_ITEM("OutDestUnreachs", ICMP_MIB_OUTDESTUNREACHS),
-	SNMP_MIB_ITEM("OutTimeExcds", ICMP_MIB_OUTTIMEEXCDS),
-	SNMP_MIB_ITEM("OutParmProbs", ICMP_MIB_OUTPARMPROBS),
-	SNMP_MIB_ITEM("OutSrcQuenchs", ICMP_MIB_OUTSRCQUENCHS),
-	SNMP_MIB_ITEM("OutRedirects", ICMP_MIB_OUTREDIRECTS),
-	SNMP_MIB_ITEM("OutEchos", ICMP_MIB_OUTECHOS),
-	SNMP_MIB_ITEM("OutEchoReps", ICMP_MIB_OUTECHOREPS),
-	SNMP_MIB_ITEM("OutTimestamps", ICMP_MIB_OUTTIMESTAMPS),
-	SNMP_MIB_ITEM("OutTimestampReps", ICMP_MIB_OUTTIMESTAMPREPS),
-	SNMP_MIB_ITEM("OutAddrMasks", ICMP_MIB_OUTADDRMASKS),
-	SNMP_MIB_ITEM("OutAddrMaskReps", ICMP_MIB_OUTADDRMASKREPS),
 	SNMP_MIB_SENTINEL
 };
 
+static struct {
+	char *name;
+	int index;
+} icmpmibmap[] = {
+	{ "DestUnreachs", ICMP_DEST_UNREACH },
+	{ "TimeExcds", ICMP_TIME_EXCEEDED },
+	{ "ParmProbs", ICMP_PARAMETERPROB },
+	{ "SrcQuenchs", ICMP_SOURCE_QUENCH },
+	{ "Redirects", ICMP_REDIRECT },
+	{ "Echos", ICMP_ECHO },
+	{ "EchoReps", ICMP_ECHOREPLY },
+	{ "Timestamps", ICMP_TIMESTAMP },
+	{ "TimestampReps", ICMP_TIMESTAMPREPLY },
+	{ "AddrMasks", ICMP_ADDRESS },
+	{ "AddrMaskReps", ICMP_ADDRESSREPLY },
+	{ 0, 0 }
+};
+
+
 static const struct snmp_mib snmp4_tcp_list[] = {
 	SNMP_MIB_ITEM("RtoAlgorithm", TCP_MIB_RTOALGORITHM),
 	SNMP_MIB_ITEM("RtoMin", TCP_MIB_RTOMIN),
@@ -247,6 +244,72 @@ static const struct snmp_mib snmp4_net_l
 	SNMP_MIB_SENTINEL
 };
 
+static void icmpmsg_put(struct seq_file *seq)
+{
+#define PERLINE	16
+
+	int j, i, count;
+	static int out[PERLINE];
+
+	count = 0;
+	for (i = 0; i < ICMPMSG_MIB_MAX; i++) {
+
+		if (snmp_fold_field((void **) icmpmsg_statistics, i))
+			out[count++] = i;
+		if (count < PERLINE)
+			continue;
+
+		seq_printf(seq, "\nIcmpMsg:");
+		for (j = 0; j < PERLINE; ++j)
+			seq_printf(seq, " %sType%u", i & 0x100 ? "Out" : "In",
+					i & 0xff);
+		seq_printf(seq, "\nIcmpMsg: ");
+		for (j = 0; j < PERLINE; ++j)
+			seq_printf(seq, " %lu",
+				snmp_fold_field((void **) icmpmsg_statistics,
+				out[j]));
+		seq_putc(seq, '\n');
+	}
+	if (count) {
+		seq_printf(seq, "\nIcmpMsg:");
+		for (j = 0; j < count; ++j)
+			seq_printf(seq, " %sType%u", out[j] & 0x100 ? "Out" :
+				"In", out[j] & 0xff);
+		seq_printf(seq, "\nIcmpMsg:");
+		for (j = 0; j < count; ++j)
+			seq_printf(seq, " %lu", snmp_fold_field((void **)
+				icmpmsg_statistics, out[j]));
+	}
+
+#undef PERLINE
+}
+
+static void icmp_put(struct seq_file *seq)
+{
+	int i;
+
+	seq_puts(seq, "\nIcmp: InMsgs InErrors");
+	for (i=0; icmpmibmap[i].name != NULL; i++)
+		seq_printf(seq, " In%s", icmpmibmap[i].name);
+	seq_printf(seq, " OutMsgs OutErrors");
+	for (i=0; icmpmibmap[i].name != NULL; i++)
+		seq_printf(seq, " Out%s", icmpmibmap[i].name);
+	seq_printf(seq, "\nIcmp: %lu %lu",
+		snmp_fold_field((void **) icmp_statistics, ICMP_MIB_INMSGS),
+		snmp_fold_field((void **) icmp_statistics, ICMP_MIB_INERRORS));
+	for (i=0; icmpmibmap[i].name != NULL; i++)
+		seq_printf(seq, " %lu",
+			snmp_fold_field((void **) icmpmsg_statistics,
+				icmpmibmap[i].index));
+	seq_printf(seq, " %lu %lu",
+		snmp_fold_field((void **) icmp_statistics, ICMP_MIB_OUTMSGS),
+		snmp_fold_field((void **) icmp_statistics, ICMP_MIB_OUTERRORS));
+	for (i=0; icmpmibmap[i].name != NULL; i++)
+		seq_printf(seq, " %lu",
+			snmp_fold_field((void **) icmpmsg_statistics,
+				icmpmibmap[i].index));
+}
+
 /*
  *	Called from the PROCfs module. This outputs /proc/net/snmp.
  */
@@ -267,15 +330,8 @@ static int snmp_seq_show(struct seq_file
 			   snmp_fold_field((void **)ip_statistics,
 					   snmp4_ipstats_list[i].entry));
 
-	seq_puts(seq, "\nIcmp:");
-	for (i = 0; snmp4_icmp_list[i].name != NULL; i++)
-		seq_printf(seq, " %s", snmp4_icmp_list[i].name);
-
-	seq_puts(seq, "\nIcmp:");
-	for (i = 0; snmp4_icmp_list[i].name != NULL; i++)
-		seq_printf(seq, " %lu",
-			   snmp_fold_field((void **)icmp_statistics,
-					   snmp4_icmp_list[i].entry));
+	icmp_put(seq);	/* RFC 2011 compatibility */
+	icmpmsg_put(seq);
 
 	seq_puts(seq, "\nTcp:");
 	for (i = 0; snmp4_tcp_list[i].name != NULL; i++)
@@ -332,6 +388,8 @@ static const struct file_operations snmp
 	.release = single_release,
 };
 
+
+
 /*
  *	Output /proc/net/netstat
  */
diff -ruNp linux-2.6.22.5/net/ipv4/raw.c linux-2.6.22.5_ICMPMSG/net/ipv4/raw.c
--- linux-2.6.22.5/net/ipv4/raw.c	2007-08-22 16:23:54.000000000 -0700
+++ linux-2.6.22.5_ICMPMSG/net/ipv4/raw.c	2007-08-23 15:54:12.000000000 -0700
@@ -313,6 +313,9 @@ static int raw_send_hdrinc(struct sock *
 
 		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 	}
+	if (iph->protocol == IPPROTO_ICMP)
+		icmp_out_count(((struct icmphdr *)
+			skb_transport_header(skb))->type);
 
 	err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
 		      dst_output);
