[nss-ecm] Enhanced Connection Manager

Provides initial functionality for the Enhanced Connection Manager.

Change-Id: I9a9258bf6386cc691f1a80ccc69aa063938e5a5e
Signed-off-by: Ben Menchaca <bmenchac@codeaurora.org>
diff --git a/ecm_tracker.c b/ecm_tracker.c
new file mode 100644
index 0000000..47730f7
--- /dev/null
+++ b/ecm_tracker.c
@@ -0,0 +1,1083 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2014, The Linux Foundation.  All rights reserved.
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all copies.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ **************************************************************************
+ */
+
+#include <linux/types.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/icmp.h>
+#include <linux/sysctl.h>
+#include <linux/kthread.h>
+#include <linux/sysdev.h>
+#include <linux/fs.h>
+#include <linux/pkt_sched.h>
+#include <linux/string.h>
+#include <net/route.h>
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <asm/unaligned.h>
+#include <asm/uaccess.h>	/* for put_user */
+#include <net/ipv6.h>
+#include <linux/inet.h>
+#include <linux/in.h>
+#include <linux/udp.h>
+#include <linux/tcp.h>
+
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_bridge.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_conntrack_l4proto.h>
+#include <net/netfilter/nf_conntrack_l3proto.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
+#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
+
+/*
+ * Debug output levels
+ * 0 = OFF
+ * 1 = ASSERTS / ERRORS
+ * 2 = 1 + WARN
+ * 3 = 2 + INFO
+ * 4 = 3 + TRACE
+ */
+#define DEBUG_LEVEL ECM_TRACKER_DEBUG_LEVEL
+
+#include "ecm_types.h"
+#include "ecm_db_types.h"
+#include "ecm_tracker.h"
+
+int ecm_tracker_data_total = 0;				/* Data total for all skb list instances */
+int ecm_tracker_data_buffer_total = 0;			/* Data buffer total allocated for all skb list instances */
+int ecm_tracker_data_limit = ECM_TRACKER_GLOBAL_DATA_LIMIT_DEFAULT;
+int ecm_tracker_data_buffer_limit = ECM_TRACKER_GLOBAL_DATA_BUFFER_LIMIT_DEFAULT;
+							/* Tracked limit for data across all instances */
+spinlock_t ecm_tracker_lock;				/* Global lock for the tracker globals */
+
+struct ecm_tracker_ip_protocols;
+
+typedef bool (*ecm_tracker_ip_header_helper_method_t)(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr);
+							/* A header helper method is used to inspect a protocol header, determine if it is valid, its size etc. and where any next header will be esp. important for IPv6 */
+
+/*
+ * Forward references for the header helpers
+ */
+static bool ecm_tracker_ip_header_helper_tcp(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr);
+static bool ecm_tracker_ip_header_helper_udp(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr);
+static bool ecm_tracker_ip_header_helper_icmp(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr);
+static bool ecm_tracker_ip_header_helper_unknown(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr);
+static bool ecm_tracker_ip_header_helper_ipv6_generic(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr);
+static bool ecm_tracker_ip_header_helper_ipv6_fragment(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr);
+static bool ecm_tracker_ip_header_helper_gre(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr);
+static bool ecm_tracker_ip_header_helper_ah(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr);
+static bool ecm_tracker_ip_header_helper_ipv6_icmp(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr);
+
+/*
+ * struct ecm_tracker_ip_protocols_known[]
+ *	A list of protocols known to the tracker and which it will record the location of in its ecm_tracker_ip_header.
+ *
+ * This is especially important for IPv6 which can have multiple headers in its packet.
+ */
+static struct ecm_tracker_ip_protocols {
+	uint8_t ip_protocol;					/* The IP protocol we want to detect and record its information */
+	ecm_tracker_ip_protocol_type_t ecm_ip_protocol;		/* The ECM Tracker protocol identifier equivalent */
+	char *name;						/* Visual name of the protocol */
+	ecm_tracker_ip_header_helper_method_t header_helper;	/* A function used to help process the header, e.g. its size etc. When a NULL helper is located, header processing stops. */
+} ecm_tracker_ip_protocols_known[256] =
+{
+	{0, ECM_TRACKER_IP_PROTOCOL_TYPE_IPV6_HBH, "ipv6_hbh", ecm_tracker_ip_header_helper_ipv6_generic},
+	{1, ECM_TRACKER_IP_PROTOCOL_TYPE_ICMP, "icmp", ecm_tracker_ip_header_helper_icmp},
+	{2, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "2", ecm_tracker_ip_header_helper_unknown},
+	{3, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "3", ecm_tracker_ip_header_helper_unknown},
+	{4, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "4", ecm_tracker_ip_header_helper_unknown},
+	{5, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "5", ecm_tracker_ip_header_helper_unknown},
+	{6, ECM_TRACKER_IP_PROTOCOL_TYPE_TCP, "tcp", ecm_tracker_ip_header_helper_tcp},
+	{7, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "7", ecm_tracker_ip_header_helper_unknown},
+	{8, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "8", ecm_tracker_ip_header_helper_unknown},
+	{9, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "9", ecm_tracker_ip_header_helper_unknown},
+	{10, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "10", ecm_tracker_ip_header_helper_unknown},
+	{11, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "11", ecm_tracker_ip_header_helper_unknown},
+	{12, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "12", ecm_tracker_ip_header_helper_unknown},
+	{13, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "13", ecm_tracker_ip_header_helper_unknown},
+	{14, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "14", ecm_tracker_ip_header_helper_unknown},
+	{15, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "15", ecm_tracker_ip_header_helper_unknown},
+	{16, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "16", ecm_tracker_ip_header_helper_unknown},
+	{17, ECM_TRACKER_IP_PROTOCOL_TYPE_UDP, "udp", ecm_tracker_ip_header_helper_udp},
+	{18, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "18", ecm_tracker_ip_header_helper_unknown},
+	{19, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "19", ecm_tracker_ip_header_helper_unknown},
+	{20, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "20", ecm_tracker_ip_header_helper_unknown},
+	{21, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "21", ecm_tracker_ip_header_helper_unknown},
+	{22, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "22", ecm_tracker_ip_header_helper_unknown},
+	{23, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "23", ecm_tracker_ip_header_helper_unknown},
+	{24, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "24", ecm_tracker_ip_header_helper_unknown},
+	{25, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "25", ecm_tracker_ip_header_helper_unknown},
+	{26, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "26", ecm_tracker_ip_header_helper_unknown},
+	{27, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "27", ecm_tracker_ip_header_helper_unknown},
+	{28, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "28", ecm_tracker_ip_header_helper_unknown},
+	{29, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "29", ecm_tracker_ip_header_helper_unknown},
+	{30, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "30", ecm_tracker_ip_header_helper_unknown},
+	{31, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "31", ecm_tracker_ip_header_helper_unknown},
+	{32, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "32", ecm_tracker_ip_header_helper_unknown},
+	{33, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "33", ecm_tracker_ip_header_helper_unknown},
+	{34, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "34", ecm_tracker_ip_header_helper_unknown},
+	{35, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "35", ecm_tracker_ip_header_helper_unknown},
+	{36, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "36", ecm_tracker_ip_header_helper_unknown},
+	{37, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "37", ecm_tracker_ip_header_helper_unknown},
+	{38, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "38", ecm_tracker_ip_header_helper_unknown},
+	{39, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "39", ecm_tracker_ip_header_helper_unknown},
+	{40, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "40", ecm_tracker_ip_header_helper_unknown},
+	{41, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "41", ecm_tracker_ip_header_helper_unknown},
+	{42, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "42", ecm_tracker_ip_header_helper_unknown},
+	{43, ECM_TRACKER_IP_PROTOCOL_TYPE_IPV6_ROUTING, "ipv6_routing", ecm_tracker_ip_header_helper_ipv6_generic},
+	{44, ECM_TRACKER_IP_PROTOCOL_TYPE_IPV6_FRAGMENT, "ipv6_fragment", ecm_tracker_ip_header_helper_ipv6_fragment},
+	{45, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "45", ecm_tracker_ip_header_helper_unknown},
+	{46, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "46", ecm_tracker_ip_header_helper_unknown},
+	{47, ECM_TRACKER_IP_PROTOCOL_TYPE_GRE, "gre", ecm_tracker_ip_header_helper_gre},
+	{48, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "48", ecm_tracker_ip_header_helper_unknown},
+	{49, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "49", ecm_tracker_ip_header_helper_unknown},
+	{50, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "50", ecm_tracker_ip_header_helper_unknown},
+	{51, ECM_TRACKER_IP_PROTOCOL_TYPE_AH, "ah", ecm_tracker_ip_header_helper_ah},
+	{52, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "52", ecm_tracker_ip_header_helper_unknown},
+	{53, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "53", ecm_tracker_ip_header_helper_unknown},
+	{54, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "54", ecm_tracker_ip_header_helper_unknown},
+	{55, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "55", ecm_tracker_ip_header_helper_unknown},
+	{56, ECM_TRACKER_IP_PROTOCOL_TYPE_IPV6_ICMP, "ipv6_icmp", ecm_tracker_ip_header_helper_ipv6_icmp},
+	{57, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "57", ecm_tracker_ip_header_helper_unknown},
+	{58, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "58", ecm_tracker_ip_header_helper_unknown},
+	{59, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "59", ecm_tracker_ip_header_helper_unknown},
+	{60, ECM_TRACKER_IP_PROTOCOL_TYPE_IPV6_DO, "ipv6_do", ecm_tracker_ip_header_helper_ipv6_generic},
+	{61, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "61", ecm_tracker_ip_header_helper_unknown},
+	{62, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "62", ecm_tracker_ip_header_helper_unknown},
+	{63, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "63", ecm_tracker_ip_header_helper_unknown},
+	{64, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "64", ecm_tracker_ip_header_helper_unknown},
+	{65, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "65", ecm_tracker_ip_header_helper_unknown},
+	{66, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "66", ecm_tracker_ip_header_helper_unknown},
+	{67, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "67", ecm_tracker_ip_header_helper_unknown},
+	{68, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "68", ecm_tracker_ip_header_helper_unknown},
+	{69, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "69", ecm_tracker_ip_header_helper_unknown},
+	{70, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "70", ecm_tracker_ip_header_helper_unknown},
+	{71, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "71", ecm_tracker_ip_header_helper_unknown},
+	{72, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "72", ecm_tracker_ip_header_helper_unknown},
+	{73, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "73", ecm_tracker_ip_header_helper_unknown},
+	{74, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "74", ecm_tracker_ip_header_helper_unknown},
+	{75, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "75", ecm_tracker_ip_header_helper_unknown},
+	{76, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "76", ecm_tracker_ip_header_helper_unknown},
+	{77, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "77", ecm_tracker_ip_header_helper_unknown},
+	{78, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "78", ecm_tracker_ip_header_helper_unknown},
+	{79, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "79", ecm_tracker_ip_header_helper_unknown},
+	{80, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "80", ecm_tracker_ip_header_helper_unknown},
+	{81, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "81", ecm_tracker_ip_header_helper_unknown},
+	{82, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "82", ecm_tracker_ip_header_helper_unknown},
+	{83, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "83", ecm_tracker_ip_header_helper_unknown},
+	{84, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "84", ecm_tracker_ip_header_helper_unknown},
+	{85, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "85", ecm_tracker_ip_header_helper_unknown},
+	{86, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "86", ecm_tracker_ip_header_helper_unknown},
+	{87, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "87", ecm_tracker_ip_header_helper_unknown},
+	{88, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "88", ecm_tracker_ip_header_helper_unknown},
+	{89, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "89", ecm_tracker_ip_header_helper_unknown},
+	{90, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "90", ecm_tracker_ip_header_helper_unknown},
+	{91, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "91", ecm_tracker_ip_header_helper_unknown},
+	{92, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "92", ecm_tracker_ip_header_helper_unknown},
+	{93, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "93", ecm_tracker_ip_header_helper_unknown},
+	{94, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "94", ecm_tracker_ip_header_helper_unknown},
+	{95, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "95", ecm_tracker_ip_header_helper_unknown},
+	{96, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "96", ecm_tracker_ip_header_helper_unknown},
+	{97, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "97", ecm_tracker_ip_header_helper_unknown},
+	{98, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "98", ecm_tracker_ip_header_helper_unknown},
+	{99, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "99", ecm_tracker_ip_header_helper_unknown},
+	{100, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "100", ecm_tracker_ip_header_helper_unknown},
+	{101, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "101", ecm_tracker_ip_header_helper_unknown},
+	{102, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "102", ecm_tracker_ip_header_helper_unknown},
+	{103, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "103", ecm_tracker_ip_header_helper_unknown},
+	{104, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "104", ecm_tracker_ip_header_helper_unknown},
+	{105, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "105", ecm_tracker_ip_header_helper_unknown},
+	{106, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "106", ecm_tracker_ip_header_helper_unknown},
+	{107, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "107", ecm_tracker_ip_header_helper_unknown},
+	{108, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "108", ecm_tracker_ip_header_helper_unknown},
+	{109, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "109", ecm_tracker_ip_header_helper_unknown},
+	{110, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "110", ecm_tracker_ip_header_helper_unknown},
+	{111, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "111", ecm_tracker_ip_header_helper_unknown},
+	{112, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "112", ecm_tracker_ip_header_helper_unknown},
+	{113, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "113", ecm_tracker_ip_header_helper_unknown},
+	{114, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "114", ecm_tracker_ip_header_helper_unknown},
+	{115, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "115", ecm_tracker_ip_header_helper_unknown},
+	{116, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "116", ecm_tracker_ip_header_helper_unknown},
+	{117, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "117", ecm_tracker_ip_header_helper_unknown},
+	{118, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "118", ecm_tracker_ip_header_helper_unknown},
+	{119, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "119", ecm_tracker_ip_header_helper_unknown},
+	{120, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "120", ecm_tracker_ip_header_helper_unknown},
+	{121, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "121", ecm_tracker_ip_header_helper_unknown},
+	{122, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "122", ecm_tracker_ip_header_helper_unknown},
+	{123, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "123", ecm_tracker_ip_header_helper_unknown},
+	{124, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "124", ecm_tracker_ip_header_helper_unknown},
+	{125, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "125", ecm_tracker_ip_header_helper_unknown},
+	{126, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "126", ecm_tracker_ip_header_helper_unknown},
+	{127, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "127", ecm_tracker_ip_header_helper_unknown},
+	{128, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "128", ecm_tracker_ip_header_helper_unknown},
+	{129, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "129", ecm_tracker_ip_header_helper_unknown},
+	{130, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "130", ecm_tracker_ip_header_helper_unknown},
+	{131, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "131", ecm_tracker_ip_header_helper_unknown},
+	{132, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "132", ecm_tracker_ip_header_helper_unknown},
+	{133, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "133", ecm_tracker_ip_header_helper_unknown},
+	{134, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "134", ecm_tracker_ip_header_helper_unknown},
+	{135, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "135", ecm_tracker_ip_header_helper_unknown},
+	{136, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "136", ecm_tracker_ip_header_helper_unknown},
+	{137, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "137", ecm_tracker_ip_header_helper_unknown},
+	{138, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "138", ecm_tracker_ip_header_helper_unknown},
+	{139, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "139", ecm_tracker_ip_header_helper_unknown},
+	{140, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "140", ecm_tracker_ip_header_helper_unknown},
+	{141, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "141", ecm_tracker_ip_header_helper_unknown},
+	{142, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "142", ecm_tracker_ip_header_helper_unknown},
+	{143, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "143", ecm_tracker_ip_header_helper_unknown},
+	{144, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "144", ecm_tracker_ip_header_helper_unknown},
+	{145, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "145", ecm_tracker_ip_header_helper_unknown},
+	{146, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "146", ecm_tracker_ip_header_helper_unknown},
+	{147, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "147", ecm_tracker_ip_header_helper_unknown},
+	{148, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "148", ecm_tracker_ip_header_helper_unknown},
+	{149, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "149", ecm_tracker_ip_header_helper_unknown},
+	{150, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "150", ecm_tracker_ip_header_helper_unknown},
+	{151, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "151", ecm_tracker_ip_header_helper_unknown},
+	{152, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "152", ecm_tracker_ip_header_helper_unknown},
+	{153, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "153", ecm_tracker_ip_header_helper_unknown},
+	{154, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "154", ecm_tracker_ip_header_helper_unknown},
+	{155, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "155", ecm_tracker_ip_header_helper_unknown},
+	{156, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "156", ecm_tracker_ip_header_helper_unknown},
+	{157, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "157", ecm_tracker_ip_header_helper_unknown},
+	{158, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "158", ecm_tracker_ip_header_helper_unknown},
+	{159, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "159", ecm_tracker_ip_header_helper_unknown},
+	{160, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "160", ecm_tracker_ip_header_helper_unknown},
+	{161, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "161", ecm_tracker_ip_header_helper_unknown},
+	{162, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "162", ecm_tracker_ip_header_helper_unknown},
+	{163, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "163", ecm_tracker_ip_header_helper_unknown},
+	{164, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "164", ecm_tracker_ip_header_helper_unknown},
+	{165, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "165", ecm_tracker_ip_header_helper_unknown},
+	{166, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "166", ecm_tracker_ip_header_helper_unknown},
+	{167, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "167", ecm_tracker_ip_header_helper_unknown},
+	{168, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "168", ecm_tracker_ip_header_helper_unknown},
+	{169, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "169", ecm_tracker_ip_header_helper_unknown},
+	{170, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "170", ecm_tracker_ip_header_helper_unknown},
+	{171, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "171", ecm_tracker_ip_header_helper_unknown},
+	{172, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "172", ecm_tracker_ip_header_helper_unknown},
+	{173, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "173", ecm_tracker_ip_header_helper_unknown},
+	{174, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "174", ecm_tracker_ip_header_helper_unknown},
+	{175, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "175", ecm_tracker_ip_header_helper_unknown},
+	{176, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "176", ecm_tracker_ip_header_helper_unknown},
+	{177, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "177", ecm_tracker_ip_header_helper_unknown},
+	{178, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "178", ecm_tracker_ip_header_helper_unknown},
+	{179, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "179", ecm_tracker_ip_header_helper_unknown},
+	{180, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "180", ecm_tracker_ip_header_helper_unknown},
+	{181, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "181", ecm_tracker_ip_header_helper_unknown},
+	{182, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "182", ecm_tracker_ip_header_helper_unknown},
+	{183, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "183", ecm_tracker_ip_header_helper_unknown},
+	{184, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "184", ecm_tracker_ip_header_helper_unknown},
+	{185, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "185", ecm_tracker_ip_header_helper_unknown},
+	{186, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "186", ecm_tracker_ip_header_helper_unknown},
+	{187, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "187", ecm_tracker_ip_header_helper_unknown},
+	{188, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "188", ecm_tracker_ip_header_helper_unknown},
+	{189, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "189", ecm_tracker_ip_header_helper_unknown},
+	{190, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "190", ecm_tracker_ip_header_helper_unknown},
+	{191, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "191", ecm_tracker_ip_header_helper_unknown},
+	{192, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "192", ecm_tracker_ip_header_helper_unknown},
+	{193, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "193", ecm_tracker_ip_header_helper_unknown},
+	{194, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "194", ecm_tracker_ip_header_helper_unknown},
+	{195, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "195", ecm_tracker_ip_header_helper_unknown},
+	{196, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "196", ecm_tracker_ip_header_helper_unknown},
+	{197, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "197", ecm_tracker_ip_header_helper_unknown},
+	{198, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "198", ecm_tracker_ip_header_helper_unknown},
+	{199, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "199", ecm_tracker_ip_header_helper_unknown},
+	{200, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "200", ecm_tracker_ip_header_helper_unknown},
+	{201, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "201", ecm_tracker_ip_header_helper_unknown},
+	{202, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "202", ecm_tracker_ip_header_helper_unknown},
+	{203, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "203", ecm_tracker_ip_header_helper_unknown},
+	{204, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "204", ecm_tracker_ip_header_helper_unknown},
+	{205, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "205", ecm_tracker_ip_header_helper_unknown},
+	{206, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "206", ecm_tracker_ip_header_helper_unknown},
+	{207, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "207", ecm_tracker_ip_header_helper_unknown},
+	{208, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "208", ecm_tracker_ip_header_helper_unknown},
+	{209, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "209", ecm_tracker_ip_header_helper_unknown},
+	{210, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "210", ecm_tracker_ip_header_helper_unknown},
+	{211, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "211", ecm_tracker_ip_header_helper_unknown},
+	{212, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "212", ecm_tracker_ip_header_helper_unknown},
+	{213, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "213", ecm_tracker_ip_header_helper_unknown},
+	{214, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "214", ecm_tracker_ip_header_helper_unknown},
+	{215, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "215", ecm_tracker_ip_header_helper_unknown},
+	{216, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "216", ecm_tracker_ip_header_helper_unknown},
+	{217, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "217", ecm_tracker_ip_header_helper_unknown},
+	{218, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "218", ecm_tracker_ip_header_helper_unknown},
+	{219, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "219", ecm_tracker_ip_header_helper_unknown},
+	{220, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "220", ecm_tracker_ip_header_helper_unknown},
+	{221, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "221", ecm_tracker_ip_header_helper_unknown},
+	{222, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "222", ecm_tracker_ip_header_helper_unknown},
+	{223, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "223", ecm_tracker_ip_header_helper_unknown},
+	{224, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "224", ecm_tracker_ip_header_helper_unknown},
+	{225, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "225", ecm_tracker_ip_header_helper_unknown},
+	{226, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "226", ecm_tracker_ip_header_helper_unknown},
+	{227, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "227", ecm_tracker_ip_header_helper_unknown},
+	{228, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "228", ecm_tracker_ip_header_helper_unknown},
+	{229, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "229", ecm_tracker_ip_header_helper_unknown},
+	{230, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "230", ecm_tracker_ip_header_helper_unknown},
+	{231, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "231", ecm_tracker_ip_header_helper_unknown},
+	{232, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "232", ecm_tracker_ip_header_helper_unknown},
+	{233, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "233", ecm_tracker_ip_header_helper_unknown},
+	{234, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "234", ecm_tracker_ip_header_helper_unknown},
+	{235, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "235", ecm_tracker_ip_header_helper_unknown},
+	{236, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "236", ecm_tracker_ip_header_helper_unknown},
+	{237, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "237", ecm_tracker_ip_header_helper_unknown},
+	{238, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "238", ecm_tracker_ip_header_helper_unknown},
+	{239, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "239", ecm_tracker_ip_header_helper_unknown},
+	{240, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "240", ecm_tracker_ip_header_helper_unknown},
+	{241, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "241", ecm_tracker_ip_header_helper_unknown},
+	{242, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "242", ecm_tracker_ip_header_helper_unknown},
+	{243, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "243", ecm_tracker_ip_header_helper_unknown},
+	{244, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "244", ecm_tracker_ip_header_helper_unknown},
+	{245, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "245", ecm_tracker_ip_header_helper_unknown},
+	{246, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "246", ecm_tracker_ip_header_helper_unknown},
+	{247, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "247", ecm_tracker_ip_header_helper_unknown},
+	{248, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "248", ecm_tracker_ip_header_helper_unknown},
+	{249, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "249", ecm_tracker_ip_header_helper_unknown},
+	{250, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "250", ecm_tracker_ip_header_helper_unknown},
+	{251, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "251", ecm_tracker_ip_header_helper_unknown},
+	{252, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "252", ecm_tracker_ip_header_helper_unknown},
+	{253, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "253", ecm_tracker_ip_header_helper_unknown},
+	{254, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "254", ecm_tracker_ip_header_helper_unknown},
+	{255, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "255", ecm_tracker_ip_header_helper_unknown}
+};
+
+/*
+ * ecm_tracker_ip_check_header_and_read()
+ *	Check that we have a complete network-level IPv4 or V6 header, check it and return true if so.
+ */
+bool ecm_tracker_ip_check_header_and_read(struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb)
+{
+	struct iphdr *v4_hdr;
+	struct ipv6hdr *v6_hdr;
+	int16_t this_header;
+	uint32_t offset;
+	uint16_t remain;
+
+	memset(ip_hdr, 0, sizeof(*ip_hdr));
+
+	ip_hdr->skb = skb;
+
+	/*
+	 * Dealing with IPv4 or IPv6?
+	 */
+	v4_hdr = skb_header_pointer(skb, 0, sizeof(struct iphdr), &ip_hdr->h.v4_hdr);
+	if (v4_hdr && (v4_hdr->version == 4)) {
+		DEBUG_TRACE("%p: skb: %p is ipv4\n", ip_hdr, skb);
+		ip_hdr->is_v4 = true;
+	} else {
+		/*
+		 * Try V6
+		 */
+		DEBUG_TRACE("skb: %p contains no v4 header\n", skb);
+		v6_hdr = skb_header_pointer(skb, 0, sizeof(struct ipv6hdr), &ip_hdr->h.v6_hdr);
+		if (!v6_hdr || (v6_hdr->version != 6)) {
+			DEBUG_TRACE("skb: %p contains no v6 header\n", skb);
+			return false;
+		}
+		DEBUG_TRACE("%p: skb: %p is ipv6\n", ip_hdr, skb);
+		ip_hdr->is_v4 = false;
+	}
+
+	if (ip_hdr->is_v4) {
+		uint8_t protocol;
+		int16_t next_unused;
+		ecm_tracker_ip_protocol_type_t ecm_ip_protocol;
+		struct ecm_tracker_ip_protocols *etip;
+		struct ecm_tracker_ip_protocol_header *etiph;
+
+		DEBUG_TRACE("%p: skb: %p ipv4\n", ip_hdr, skb);
+
+		/*
+		 * Process IPv4
+		 */
+		ECM_NIN4_ADDR_TO_IP_ADDR(ip_hdr->src_addr, v4_hdr->saddr);
+		ECM_NIN4_ADDR_TO_IP_ADDR(ip_hdr->dest_addr, v4_hdr->daddr);
+		ip_hdr->ip_header_length = v4_hdr->ihl;
+		ip_hdr->ip_header_length <<= 2;
+		if (ip_hdr->ip_header_length < 20) {
+			DEBUG_WARN("%p: v4 invalid ip hdr len %d\n", skb, ip_hdr->ip_header_length);
+			return false;
+		}
+		ip_hdr->total_length = ntohs(v4_hdr->tot_len);
+		if (skb->len < ip_hdr->total_length) {
+			DEBUG_WARN("%p: v4 invalid total len: %u skb len: %u\n", skb, ip_hdr->total_length, skb->len);
+			return false;
+		}
+		remain = ip_hdr->total_length - ip_hdr->ip_header_length;
+
+		/*
+		 * Fragmented?
+		 */
+		ip_hdr->fragmented = (ntohs(v4_hdr->frag_off) & 0x3fff)? true : false;
+
+		/*
+		 * Get the protocol and where the header info will be stored
+		 */
+		protocol = v4_hdr->protocol;
+		ip_hdr->protocol = (int)v4_hdr->protocol;
+		etip = &ecm_tracker_ip_protocols_known[protocol];	/* Get header helper */
+		ecm_ip_protocol = etip->ecm_ip_protocol;
+		etiph = &ip_hdr->headers[ecm_ip_protocol];		/* Get where the header detail is stored in ip_hdr->headers[] */
+
+		DEBUG_TRACE("%p: v4 skb: %p, len: %d, ip_header_length: %u, total_length: %u, remain: %u, fragmented: %04x, protocol: %u, ecm_ip_protocol: %d src_addr: "
+				ECM_IP_ADDR_DOT_FMT ", dest addr: " ECM_IP_ADDR_DOT_FMT "\n",
+				ip_hdr,
+				skb,
+				skb->len,
+				ip_hdr->ip_header_length,
+				ip_hdr->total_length,
+				remain,
+				ip_hdr->fragmented,
+				ip_hdr->protocol,
+				ecm_ip_protocol,
+				ECM_IP_ADDR_TO_DOT(ip_hdr->src_addr),
+				ECM_IP_ADDR_TO_DOT(ip_hdr->dest_addr));
+
+		/*
+		 * Populate protocol detail
+		 * IPv4 can only have one.
+		 */
+		if (!etip->header_helper(
+				etip,
+				etiph,
+				ip_hdr,
+				skb,
+				(uint8_t)ip_hdr->protocol,
+				ecm_ip_protocol,
+				ip_hdr->ip_header_length,
+				remain,
+				&next_unused)) {
+			DEBUG_WARN("%p: v4 header helper failed for: %u\n", skb, protocol);
+			return false;
+		}
+		
+		return true;
+	}
+
+	/*
+	 * IPv6
+	 */
+	ECM_NIN6_ADDR_TO_IP_ADDR(ip_hdr->src_addr, v6_hdr->saddr);
+	ECM_NIN6_ADDR_TO_IP_ADDR(ip_hdr->dest_addr, v6_hdr->daddr);
+	ip_hdr->ip_header_length = 40;
+	remain = ntohs(v6_hdr->payload_len);
+	ip_hdr->total_length = remain + 40;
+	if (skb->len < ip_hdr->total_length) {
+		DEBUG_WARN("%p: v6 invalid total len: %u skb len: %u\n", skb, ip_hdr->total_length, skb->len);
+		return false;
+	}
+
+	/*
+	 * Process headers until we run out of space, error, or we get the no next header marker for v6 (protocol 59).
+	 */
+	offset = 40;
+	this_header = (int16_t)v6_hdr->nexthdr;
+	while ((remain > 0) && (this_header >= 0) && (this_header != 59)) {
+		struct ecm_tracker_ip_protocols *etip;
+		struct ecm_tracker_ip_protocol_header *etiph;
+		ecm_tracker_ip_protocol_type_t ecm_ip_protocol;
+		int16_t next_header;
+
+		etip = &ecm_tracker_ip_protocols_known[this_header];	/* Get header helper */
+		ecm_ip_protocol = etip->ecm_ip_protocol;
+		etiph = &ip_hdr->headers[ecm_ip_protocol];		/* Get where the header detail is stored in ip_hdr->headers[] */
+
+		/*
+		 * If this IP header has already been seen then we abort
+		 */
+		if (etiph->size) {
+			DEBUG_WARN("v6 skb: %p, protocol: %d already seen at offset: %u, size: %u\n",
+					skb, this_header, etiph->offset, etiph->size);
+			return false;
+		}
+		if (!etip->header_helper(
+				etip,
+				etiph,
+				ip_hdr,
+				skb,
+				(uint8_t)this_header,
+				ecm_ip_protocol,
+				offset,
+				remain,
+				&next_header)) {
+			DEBUG_WARN("%p: v6 header helper failed for: %d\n", skb, this_header);
+			return false;
+		}
+
+		offset += etiph->size;
+		DEBUG_ASSERT(remain >= etiph->size, "v6 remain: %u goes negative after header size: %u", remain, etiph->size);
+		remain -= etiph->size;
+
+		this_header = next_header;
+	}
+
+	/*
+	 * Generally the last protocol seen is the upper layer protocol
+	 */
+	ip_hdr->protocol = (int)this_header;
+
+	return ip_hdr;
+}
+EXPORT_SYMBOL(ecm_tracker_ip_check_header_and_read);
+
+/*
+ * ecm_tracker_ip_header_helper_ipv6_generic()
+ *	Interpret a Generic IPv6 extension header
+ */
+static bool ecm_tracker_ip_header_helper_ipv6_generic(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr,
+						struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr)
+{
+	struct ipv6_gen_hdr {
+		uint8_t next_protocol;
+		uint8_t header_ext_len;
+	} gen_header_buffer;
+	struct ipv6_gen_hdr *gen_header;
+	uint16_t hdr_size;
+
+	/*
+	 * At least 8 bytes
+	 */
+	if (remain < 8) {
+		return false;
+	}
+
+	gen_header = skb_header_pointer(skb, offset, sizeof(struct ipv6_gen_hdr), &gen_header_buffer);
+	if (!gen_header) {
+		return false;
+	}
+	hdr_size = gen_header->header_ext_len;
+	hdr_size <<= 3;
+	hdr_size += 8;
+	if (remain < hdr_size) {
+		DEBUG_WARN("IPv6 extension: %p packet remain: %u too small for tcp header: %u\n", skb, remain, hdr_size);
+		return false;
+	}
+	if (unlikely(ip_hdr->total_length < (offset + hdr_size))) {
+		DEBUG_WARN("TCP packet %p too short (total_length: %u, require: %u)\n", skb, ip_hdr->total_length, offset + hdr_size);
+		return false;
+	}
+
+	etiph->protocol_number = protocol;
+	etiph->header_size = hdr_size;
+	etiph->size = hdr_size;
+	etiph->offset = offset;
+
+	*next_hdr = (int16_t)gen_header->next_protocol;
+	return true;	
+}
+
+/*
+ * ecm_tracker_ip_header_helper_ipv6_fragment()
+ *	Interpret a Generic IPv6 fragment header
+ */
+static bool ecm_tracker_ip_header_helper_ipv6_fragment(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr,
+							struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr)
+{
+	struct ipv6_gen_hdr {
+		uint8_t next_protocol;
+		uint8_t reserved;
+	} gen_header_buffer;
+	struct ipv6_gen_hdr *gen_header;
+
+	/*
+	 * At least 8 bytes
+	 */
+	if (remain < 8) {
+		return false;
+	}
+
+	gen_header = skb_header_pointer(skb, offset, sizeof(struct ipv6_gen_hdr), &gen_header_buffer);
+	if (!gen_header) {
+		return false;
+	}
+	if (unlikely(ip_hdr->total_length < (offset + 8))) {
+		DEBUG_WARN("TCP packet %p too short (total_length: %u, require: %u)\n", skb, ip_hdr->total_length, offset + 8);
+		return false;
+	}
+
+	/*
+	 * The very presence of a fragmemt header says it's fragmented
+	 */
+	ip_hdr->fragmented = true;
+
+	etiph->protocol_number = protocol;
+	etiph->header_size = 8;
+	etiph->size = 8;
+	etiph->offset = offset;
+
+	*next_hdr = (int16_t)gen_header->next_protocol;
+	return true;	
+}
+
+/*
+ * ecm_tracker_ip_header_helper_tcp()
+ *	Interpret a TCP header
+ */
+static bool ecm_tracker_ip_header_helper_tcp(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr,
+						struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr)
+{
+	struct tcphdr tcp_header_buffer;
+	struct tcphdr *tcp_header;
+	uint16_t hdr_size;
+
+	DEBUG_ASSERT((protocol == IPPROTO_TCP) && (ecm_ip_protocol == ECM_TRACKER_IP_PROTOCOL_TYPE_TCP), "Bad protocol: %u or ecm_ip_protocol: %d", protocol, ecm_ip_protocol);
+
+	if (remain < 20) {
+		return false;
+	}
+
+	tcp_header = skb_header_pointer(skb, offset, sizeof(struct tcphdr), &tcp_header_buffer);
+	if (!tcp_header) {
+		return false;
+	}
+	hdr_size = tcp_header->doff;
+	hdr_size <<= 2;
+	if (hdr_size < 20) {
+		return false;
+	}
+	if (remain < hdr_size) {
+		DEBUG_WARN("TCP packet: %p packet remain: %u too small for tcp header: %u\n", skb, remain, hdr_size);
+		return false;
+	}
+	if (unlikely(ip_hdr->total_length < (offset + hdr_size))) {
+		DEBUG_WARN("TCP packet %p too short (total_length: %u, require: %u)\n", skb, ip_hdr->total_length, offset + hdr_size);
+		return false;
+	}
+
+	etiph->protocol_number = protocol;
+	etiph->header_size = hdr_size;
+	etiph->size = remain;
+	etiph->offset = offset;
+
+	/*
+	 * There is no header following a TCP header
+	 */
+	*next_hdr = -1;
+	return true;	
+}
+
+/*
+ * ecm_tracker_ip_header_helper_gre()
+ *	Interpret a GRE header
+ */
+static bool ecm_tracker_ip_header_helper_gre(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr,
+						struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr)
+{
+	uint32_t gre_hdr_buffer;
+	uint32_t *gre_hdr_ptr;
+	uint32_t gre_hdr;
+	uint16_t hdr_size;
+
+	DEBUG_ASSERT((protocol == IPPROTO_GRE) && (ecm_ip_protocol == ECM_TRACKER_IP_PROTOCOL_TYPE_GRE), "Bad protocol: %u or ecm_ip_protocol: %d", protocol, ecm_ip_protocol);
+
+	if (remain < 4) {
+		return false;
+	}
+
+	gre_hdr_ptr = skb_header_pointer(skb, offset, sizeof(gre_hdr_buffer), &gre_hdr_buffer);
+	if (!gre_hdr_ptr) {
+		return false;
+	}
+	gre_hdr = ntohl(*gre_hdr_ptr);
+	hdr_size = 4;
+	if (gre_hdr & 0x80000000) {
+		/*
+		 * Checksum
+		 */
+		hdr_size += 4;
+	}
+	if (gre_hdr & 0x20000000) {
+		/*
+		 * Key
+		 */
+		hdr_size += 4;
+	}
+	if (gre_hdr & 0x10000000) {
+		/*
+		 * Sequence
+		 */
+		hdr_size += 4;
+	}
+	if (remain < hdr_size) {
+		DEBUG_WARN("GRE packet: %p packet remain: %u too small for tcp header: %u\n", skb, remain, hdr_size);
+		return false;
+	}
+	if (unlikely(ip_hdr->total_length < (offset + hdr_size))) {
+		DEBUG_WARN("GRE packet %p too short (total_length: %u, require: %u)\n", skb, ip_hdr->total_length, offset + hdr_size);
+		return false;
+	}
+
+	etiph->protocol_number = protocol;
+	etiph->header_size = hdr_size;
+	etiph->size = remain;
+	etiph->offset = offset;
+
+	/*
+	 * There is no header following a GRE header
+	 */
+	*next_hdr = -1;
+	return true;	
+}
+
+/*
+ * ecm_tracker_ip_header_helper_ah()
+ *	Interpret an Authentication Header
+ */
+static bool ecm_tracker_ip_header_helper_ah(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr,
+						struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr)
+{
+	struct ah_gen_hdr {
+		uint8_t next_protocol;
+		uint8_t header_len;
+	} gen_header_buffer;
+	struct ah_gen_hdr *gen_header;
+	uint16_t hdr_size;
+
+	/*
+	 * At least 8 bytes
+	 */
+	if (remain < 8) {
+		return false;
+	}
+
+	gen_header = skb_header_pointer(skb, offset, sizeof(struct ah_gen_hdr), &gen_header_buffer);
+	if (!gen_header) {
+		return false;
+	}
+
+	hdr_size = gen_header->header_len + 2;
+	hdr_size <<= 2;
+
+	if (!ip_hdr->is_v4) {
+		/*
+		 * hdr_size needs to be a multiple of 8 in a v6 frame
+		 */
+		if (hdr_size % 8) {
+			DEBUG_WARN("AH packet %p not multiple of 8 for v6 frame: %u\n", skb, hdr_size);
+			return false;
+		}
+	}
+
+	if (remain < hdr_size) {
+		DEBUG_WARN("AH packet %p too short (total_length: %u, require: %u)\n", skb, ip_hdr->total_length, offset + hdr_size);
+		return false;
+	}
+	if (unlikely(ip_hdr->total_length < (offset + hdr_size))) {
+		DEBUG_WARN("AH packet %p too short (total_length: %u, require: %u)\n", skb, ip_hdr->total_length, offset + hdr_size);
+		return false;
+	}
+
+	/*
+	 * What header follows this one?
+	 */
+	*next_hdr = gen_header->next_protocol;
+
+	etiph->protocol_number = protocol;
+	etiph->header_size = hdr_size;
+	etiph->size = hdr_size;
+	etiph->offset = offset;
+	return true;	
+}
+
+/*
+ * ecm_tracker_ip_header_helper_udp()
+ *	Interpret a UDP header
+ */
+static bool ecm_tracker_ip_header_helper_udp(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr,
+						struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr)
+{
+	DEBUG_ASSERT((protocol == IPPROTO_UDP) && (ecm_ip_protocol == ECM_TRACKER_IP_PROTOCOL_TYPE_UDP), "Bad protocol: %u or ecm_ip_protocol: %d", protocol, ecm_ip_protocol);
+
+	DEBUG_TRACE("udp helper skb: %p, protocol: %u, ecm_ip_proto: %d, offset: %u, remain: %u\n", skb, protocol, ecm_ip_protocol, offset, remain);
+	if (remain < 8) {
+		DEBUG_TRACE("not enough UDP header: %u\n", remain);
+		return false;
+	}
+
+	etiph->protocol_number = protocol;
+	etiph->header_size = 8;
+	etiph->size = remain;
+	etiph->offset = offset;
+
+	/*
+	 * There is no header following a UDP header
+	 */
+	*next_hdr = -1;
+	return true;	
+}
+
+/*
+ * ecm_tracker_ip_header_helper_unknown()
+ *	Interpret a unknown header
+ */
+static bool ecm_tracker_ip_header_helper_unknown(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr,
+							struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr)
+{
+	/*
+	 * There is no header following an unknown header
+	 */
+	*next_hdr = -1;
+	etiph->protocol_number = protocol;
+	etiph->header_size = remain;
+	etiph->size = remain;
+	etiph->offset = offset;
+	return true;	
+}
+
+/*
+ * ecm_tracker_ip_header_helper_icmp()
+ *	Interpret a ICMP V4 header
+ */
+static bool ecm_tracker_ip_header_helper_icmp(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr,
+						struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr)
+{
+	struct icmphdr icmp_header_buffer;
+	struct icmphdr *icmp_header;
+
+	DEBUG_ASSERT((protocol == IPPROTO_ICMP) && (ecm_ip_protocol == ECM_TRACKER_IP_PROTOCOL_TYPE_ICMP), "Bad protocol: %u or ecm_ip_protocol: %d", protocol, ecm_ip_protocol);
+
+	if (remain < 8) {
+		return false;
+	}
+
+	icmp_header = skb_header_pointer(skb, offset, sizeof(struct icmphdr), &icmp_header_buffer);
+	if (!icmp_header) {
+		return false;
+	}
+	switch(icmp_header->type) {
+	case ICMP_SOURCE_QUENCH:
+	case ICMP_REDIRECT:
+	case ICMP_TIME_EXCEEDED:
+	case ICMP_DEST_UNREACH:
+		/*
+		 * Should be at least our 8 bytes and minimum 20 bytes for an IP header.
+		 * NOTE: We are not looking at options that extend this header!
+		 */
+		if (remain < 28) {
+			DEBUG_WARN("icmp skb: %p type: %u too small: %u\n", skb, icmp_header->type, remain);
+			return false;
+		}
+		etiph->header_size = 8;
+		etiph->size = remain;
+		break;
+
+	case ICMP_ADDRESS:
+	case ICMP_ADDRESSREPLY:
+	case ICMP_TIMESTAMP:
+		if (remain < 12) {
+			DEBUG_WARN("icmp skb: %p type: %u too small: %u\n", skb, icmp_header->type, remain);
+			return false;
+		}
+		etiph->header_size = 12;
+		etiph->size = remain;
+		break;
+	case ICMP_TIMESTAMPREPLY:
+		if (remain < 20) {
+			DEBUG_WARN("icmp skb: %p type: %u too small: %u\n", skb, icmp_header->type, remain);
+			return false;
+		}
+		etiph->header_size = 20;
+		etiph->size = remain;
+		break;
+	case ICMP_PARAMETERPROB:
+	case ICMP_INFO_REQUEST:
+	case ICMP_INFO_REPLY:
+	default:
+		etiph->header_size = 8;
+		etiph->size = remain;
+	}
+	etiph->protocol_number = protocol;
+	etiph->offset = offset;
+
+	/*
+	 * There is no header following a ICMP header
+	 */
+	*next_hdr = -1;
+	return true;	
+}
+
+/*
+ * ecm_tracker_ip_header_helper_ipv6_icmp()
+ *	Interpret a ICMP V6 header
+ */
+static bool ecm_tracker_ip_header_helper_ipv6_icmp(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr,
+						struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr)
+{
+	if (remain < 4) {
+		DEBUG_WARN("v6 icmp: %p too small: %u\n", skb, remain);
+		return false;
+	}
+
+	etiph->protocol_number = protocol;
+	etiph->header_size = 4;
+	etiph->size = remain;
+	etiph->offset = offset;
+
+	/*
+	 * There is no header following a V6 ICMP header
+	 */
+	*next_hdr = -1;
+	return true;	
+}
+
+/*
+ * ecm_tracker_data_limit_set()
+ *	Set global tracked data limit
+ */
+void ecm_tracker_data_limit_set(uint32_t limit)
+{
+	int data_limit = (int)limit;
+	DEBUG_ASSERT(data_limit > 0, "Invalid limit %d\n", data_limit);
+	spin_lock_bh(&ecm_tracker_lock);
+	ecm_tracker_data_limit = data_limit;
+	spin_unlock_bh(&ecm_tracker_lock);
+}
+EXPORT_SYMBOL(ecm_tracker_data_limit_set);
+
+/*
+ * ecm_tracker_data_limit_get()
+ *	Return global tracked data limit
+ */
+uint32_t ecm_tracker_data_limit_get(void)
+{
+	uint32_t data_total;
+	spin_lock_bh(&ecm_tracker_lock);
+	data_total = (uint32_t)ecm_tracker_data_limit;
+	spin_unlock_bh(&ecm_tracker_lock);
+	return data_total;
+}
+EXPORT_SYMBOL(ecm_tracker_data_limit_get);
+
+/*
+ * ecm_tracker_data_total_get()
+ *	Return global tracked data quantity
+ */
+uint32_t ecm_tracker_data_total_get(void)
+{
+	uint32_t data_total;
+	spin_lock_bh(&ecm_tracker_lock);
+	data_total = (uint32_t)ecm_tracker_data_total;
+	spin_unlock_bh(&ecm_tracker_lock);
+	return data_total;
+}
+EXPORT_SYMBOL(ecm_tracker_data_total_get);
+
+/*
+ * ecm_tracker_data_buffer_total_get()
+ *	Return global tracked data buffer size
+ */
+uint32_t ecm_tracker_data_buffer_total_get(void)
+{
+	uint32_t data_buffer_total;
+	spin_lock_bh(&ecm_tracker_lock);
+	data_buffer_total = (uint32_t)ecm_tracker_data_buffer_total;
+	spin_unlock_bh(&ecm_tracker_lock);
+	return data_buffer_total;
+}
+EXPORT_SYMBOL(ecm_tracker_data_buffer_total_get);
+
+/*
+ * ecm_tracker_data_total_increase()
+ *	Increase global tracked data quantity
+ *
+ * If this function returns false then the increase has been denied and tracking of that data should not occur.
+ * Therefore call this function BEFORE tracking the actual data.
+ */
+bool ecm_tracker_data_total_increase(uint32_t n, uint32_t data_buffer_size)
+{
+	spin_lock_bh(&ecm_tracker_lock);
+
+	/*
+	 * Would we exceed our global limit?
+	 */
+	DEBUG_ASSERT((ecm_tracker_data_total + (int)n) > 0, "bad total\n");
+	if (((ecm_tracker_data_buffer_total + data_buffer_size)  > ecm_tracker_data_buffer_limit)
+			|| ((ecm_tracker_data_total + n) > ecm_tracker_data_limit)) {
+		spin_unlock_bh(&ecm_tracker_lock);
+		return false;
+	}
+	ecm_tracker_data_buffer_total += data_buffer_size;
+	ecm_tracker_data_total += (int)n;
+	spin_unlock_bh(&ecm_tracker_lock);
+	return true;
+}
+EXPORT_SYMBOL(ecm_tracker_data_total_increase);
+
+/*
+ * ecm_tracker_data_total_decrease()
+ *	Decrease global tracked data quantity
+ */
+void ecm_tracker_data_total_decrease(uint32_t n, uint32_t data_buffer_size)
+{
+	spin_lock_bh(&ecm_tracker_lock);
+	ecm_tracker_data_total -= (int)n;
+	ecm_tracker_data_buffer_total -= data_buffer_size;
+	DEBUG_ASSERT(ecm_tracker_data_total >= 0, "bad total\n");
+	DEBUG_ASSERT(ecm_tracker_data_buffer_total >= 0, "bad total\n");
+	spin_unlock_bh(&ecm_tracker_lock);
+}
+EXPORT_SYMBOL(ecm_tracker_data_total_decrease);
+
+/*
+ * ecm_tracker_module_get()
+ *	Take a reference to the module
+ */
+void ecm_tracker_module_get(void)
+{
+	try_module_get(THIS_MODULE);
+}
+EXPORT_SYMBOL(ecm_tracker_module_get);
+
+/*
+ * ecm_tracker_module_put()
+ *	Release a reference to the module
+ */
+void ecm_tracker_module_put(void)
+{
+	module_put(THIS_MODULE);
+}
+EXPORT_SYMBOL(ecm_tracker_module_put);
+
+/*
+ * ecm_tracker_init()
+ */
+static int __init ecm_tracker_init(void)
+{
+	DEBUG_INFO("Tracker Module init\n");
+	spin_lock_init(&ecm_tracker_lock);
+	return 0;
+}
+
+/*
+ * ecm_tracker_exit()
+ */
+static void __exit ecm_tracker_exit(void)
+{
+	DEBUG_INFO("Tracker Module exit\n");
+}
+
+module_init(ecm_tracker_init)
+module_exit(ecm_tracker_exit)
+
+MODULE_AUTHOR("Qualcomm Atheros, Inc.");
+MODULE_DESCRIPTION("ECM Tracker");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("Dual BSD/GPL");
+#endif
+