[qca-nss-ecm] Kernel 3.14 porting work.

Makefile:
	 Add enable/disable flag for SIT interface.

ecm_classifier_default.c
ecm_conntrack_notifier.c
ecm_db.c
ecm_tracker.c
ecm_tracker_datagram.c
ecm_tracker_udp.c
	Add linux version include file.

ecm_classifier.h
	Enable/disable classifier types.

ecm_front_end_ipv4.c
	Netfilete hook changes.
	Enable/disable certain types of unsupported interfaces and classifiers.
	Net device master changes.
	Conntrack connection accounting changes.
	Ethernet MAC compare API change.

ecm_front_end_ipv6.c
	Ethernet MAC compare API change.

ecm_init.c
	Enable/disable certain types of unsupported interfaces and classifiers.

ecm_interface.c
ecm_interface.h
	Add new net device master get function to abstract kernel differences.
	Neighbor lookup changes for IPv4.
	Enable/disable certain types of unsupported interfaces.

ecm_types.h
	Add a new MAC address comparison API to abstract kernel differences.

Change-Id: I4e2e859c65afa91029268c3c0f28761fbc878c68
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
diff --git a/Makefile b/Makefile
index 73e6314..b2f2155 100755
--- a/Makefile
+++ b/Makefile
@@ -50,6 +50,15 @@
 ccflags-$(ECM_INTERFACE_PPP_ENABLE) += -DECM_INTERFACE_PPP_ENABLE
 
 # #############################################################################
+# Define ECM_INTERFACE_SIT_ENABLE=y in order
+# to enable support for SIT interface.
+# #############################################################################
+ifeq ("$(KERNELVERSION)","3.4.0")
+ECM_INTERFACE_SIT_ENABLE=y
+endif
+ccflags-$(ECM_INTERFACE_SIT_ENABLE) += -DECM_INTERFACE_SIT_ENABLE
+
+# #############################################################################
 # Define ECM_INTERFACE_VLAN_ENABLE=y in order to enable support for VLAN
 # #############################################################################
 ifeq ("$(KERNELVERSION)","3.4.0")
diff --git a/ecm_classifier.h b/ecm_classifier.h
index bcc4f28..7d43b93 100644
--- a/ecm_classifier.h
+++ b/ecm_classifier.h
@@ -25,8 +25,12 @@
 #ifdef ECM_CLASSIFIER_HYFI_ENABLE
 	ECM_CLASSIFIER_TYPE_HYFI,		/* HyFi classifier */
 #endif
+#ifdef ECM_CLASSIFIER_DSCP_ENABLE
 	ECM_CLASSIFIER_TYPE_DSCP,		/* Provides DSCP and DSCP remarking support */
+#endif
+#ifdef ECM_CLASSIFIER_NL_ENABLE
 	ECM_CLASSIFIER_TYPE_NL,			/* Provides netlink interface */
+#endif
 	ECM_CLASSIFIER_TYPES,			/* MUST BE LAST */
 };
 typedef enum ecm_classifier_types ecm_classifier_type_t;
diff --git a/ecm_classifier_default.c b/ecm_classifier_default.c
index c75814c..d2aced7 100644
--- a/ecm_classifier_default.c
+++ b/ecm_classifier_default.c
@@ -14,6 +14,7 @@
  **************************************************************************
  */
 
+#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
diff --git a/ecm_conntrack_notifier.c b/ecm_conntrack_notifier.c
index 2ba5be2..6d75833 100644
--- a/ecm_conntrack_notifier.c
+++ b/ecm_conntrack_notifier.c
@@ -19,6 +19,7 @@
  * 	Conntrack notifier functionality.
  */
 
+#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
diff --git a/ecm_db.c b/ecm_db.c
index 9d3d387..2774f9b 100644
--- a/ecm_db.c
+++ b/ecm_db.c
@@ -14,6 +14,7 @@
  **************************************************************************
  */
 
+#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
diff --git a/ecm_front_end_ipv4.c b/ecm_front_end_ipv4.c
index 8883277..a61d98f 100644
--- a/ecm_front_end_ipv4.c
+++ b/ecm_front_end_ipv4.c
@@ -14,6 +14,7 @@
  **************************************************************************
  */
 
+#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
@@ -255,8 +256,6 @@
 			done = true;
 			break;
 
-		case ECM_DB_IFACE_TYPE_ETHERNET:
-		case ECM_DB_IFACE_TYPE_LAG:
 		case ECM_DB_IFACE_TYPE_VLAN:
 #ifdef ECM_INTERFACE_VLAN_ENABLE
 			/*
@@ -266,6 +265,8 @@
 			DEBUG_TRACE("VLAN interface unsupported\n");
 			return NULL;
 #endif
+		case ECM_DB_IFACE_TYPE_ETHERNET:
+		case ECM_DB_IFACE_TYPE_LAG:
 		case ECM_DB_IFACE_TYPE_BRIDGE:
 		case ECM_DB_IFACE_TYPE_IPSEC_TUNNEL:
 			if (!ecm_interface_mac_addr_get(addr, node_addr, &on_link, gw_addr)) {
@@ -2370,7 +2371,7 @@
 			DEBUG_TRACE("%p: vlan tag: %x\n", fecui, vlan_value);
 #else
 			rule_invalid = true;
-			DEBUG_TRACE("%p: VLAN - unsupported\n", fecti);
+			DEBUG_TRACE("%p: VLAN - unsupported\n", fecui);
 #endif
 			break;
 		case ECM_DB_IFACE_TYPE_IPSEC_TUNNEL:
@@ -2532,7 +2533,7 @@
 			DEBUG_TRACE("%p: vlan tag: %x\n", fecui, vlan_value);
 #else
 			rule_invalid = true;
-			DEBUG_TRACE("%p: VLAN - unsupported\n", fecti);
+			DEBUG_TRACE("%p: VLAN - unsupported\n", fecui);
 #endif
 			break;
 		case ECM_DB_IFACE_TYPE_IPSEC_TUNNEL:
@@ -3312,6 +3313,7 @@
 }
 
 #ifdef CONFIG_IPV6_SIT_6RD
+#ifdef ECM_INTERFACE_SIT_ENABLE
 /*
  * ecm_front_end_ipv4_sit_set_peer()
  *	It will set the tunnel's peer when the tunnel is a remote any tunnel.
@@ -3383,6 +3385,7 @@
 	ecm_db_connection_interfaces_deref(from_ifaces, from_ifaces_first);
 }
 #endif
+#endif
 
 /*
  * ecm_front_end_ipv4_connection_non_ported_callback()
@@ -3843,7 +3846,7 @@
 			DEBUG_TRACE("%p: vlan tag: %x\n", fecnpi, vlan_value);
 #else
 			rule_invalid = true;
-			DEBUG_TRACE("%p: VLAN - unsupported\n", fecti);
+			DEBUG_TRACE("%p: VLAN - unsupported\n", fecnpi);
 #endif
 			break;
 		case ECM_DB_IFACE_TYPE_IPSEC_TUNNEL:
@@ -4005,7 +4008,7 @@
 			DEBUG_TRACE("%p: vlan tag: %x\n", fecnpi, vlan_value);
 #else
 			rule_invalid = true;
-			DEBUG_TRACE("%p: VLAN - unsupported\n", fecti);
+			DEBUG_TRACE("%p: VLAN - unsupported\n", fecnpi);
 #endif
 			break;
 		case ECM_DB_IFACE_TYPE_IPSEC_TUNNEL:
@@ -4817,6 +4820,8 @@
 		return (struct ecm_classifier_instance *)cnli;
 	}
 #endif
+
+#ifdef ECM_CLASSIFIER_DSCP_ENABLE
 	if (type == ECM_CLASSIFIER_TYPE_DSCP) {
 		struct ecm_classifier_dscp_instance *cdscpi;
 		cdscpi = ecm_classifier_dscp_instance_alloc(ci);
@@ -4828,6 +4833,7 @@
 		ecm_db_connection_classifier_assign(ci, (struct ecm_classifier_instance *)cdscpi);
 		return (struct ecm_classifier_instance *)cdscpi;
 	}
+#endif
 
 #ifdef ECM_CLASSIFIER_HYFI_ENABLE
 	if (type == ECM_CLASSIFIER_TYPE_HYFI) {
@@ -6912,6 +6918,7 @@
 	DEBUG_TRACE("%p: skb priority: %u\n", ci, skb->priority);
 
 #ifdef CONFIG_IPV6_SIT_6RD
+#ifdef ECM_INTERFACE_SIT_ENABLE
 	/*
 	 * SIT tunnel acceleration needs create a rule to the nss firmware if the
 	 *	tunnel's dest ip address is empty,it will get dest ip and the embedded ipv6's dest ip
@@ -6927,6 +6934,8 @@
 		feci->deref(feci);
 	}
 #endif
+#endif
+
 	/*
 	 * Accelerate?
 	 */
@@ -7359,11 +7368,19 @@
  * ecm_front_end_ipv4_post_routing_hook()
  *	Called for IP packets that are going out to interfaces after IP routing stage.
  */
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
 static unsigned int ecm_front_end_ipv4_post_routing_hook(unsigned int hooknum,
 				struct sk_buff *skb,
 				const struct net_device *in_unused,
 				const struct net_device *out,
 				int (*okfn)(struct sk_buff *))
+#else
+static unsigned int ecm_front_end_ipv4_post_routing_hook(const struct nf_hook_ops *ops,
+				struct sk_buff *skb,
+				const struct net_device *in_unused,
+				const struct net_device *out,
+				int (*okfn)(struct sk_buff *))
+#endif
 {
 	struct net_device *in;
 	bool can_accel = true;
@@ -7407,11 +7424,19 @@
  * These may have come from another bridged interface or from a non-bridged interface.
  * Conntrack information may be available or not if this skb is bridged.
  */
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
 static unsigned int ecm_front_end_ipv4_bridge_post_routing_hook(unsigned int hooknum,
 					struct sk_buff *skb,
 					const struct net_device *in_unused,
 					const struct net_device *out,
 					int (*okfn)(struct sk_buff *))
+#else
+static unsigned int ecm_front_end_ipv4_bridge_post_routing_hook(const struct nf_hook_ops *ops,
+					struct sk_buff *skb,
+					const struct net_device *in_unused,
+					const struct net_device *out,
+					int (*okfn)(struct sk_buff *))
+#endif
 {
 	struct ethhdr *skb_eth_hdr;
 	uint16_t eth_type;
@@ -7458,15 +7483,17 @@
 	 *	Process.
 	 *
 	 * Begin by identifying case 1.
-	 * NOTE: We are given 'out' (which we implicitly know is a bridge port) so out->master is the 'bridge'.
+	 * NOTE: We are given 'out' (which we implicitly know is a bridge port) so out interface's master is the 'bridge'.
 	 */
-	bridge = out->master;
+	bridge = ecm_interface_get_and_hold_dev_master((struct net_device *)out);
+	DEBUG_ASSERT(bridge, "Expected bridge\n");
 	in = dev_get_by_index(&init_net, skb->skb_iif);
 	if  (!in) {
 		/*
 		 * Case 1.
 		 */
 		DEBUG_TRACE("Local traffic: %p, ignoring traffic to bridge: %p (%s) \n", skb, bridge, bridge->name);
+		dev_put(bridge);
 		return NF_ACCEPT;
 	}
 	dev_put(in);
@@ -7477,22 +7504,25 @@
 	 * Case 3:
 	 *	If the packet was not local (case 1) or routed (case 2) then we process.
 	 */
-	in = br_port_dev_get(out->master, skb_eth_hdr->h_source);
+	in = br_port_dev_get(bridge, skb_eth_hdr->h_source);
 	if (!in) {
 		DEBUG_TRACE("skb: %p, no in device for bridge: %p (%s)\n", skb, bridge, bridge->name);
+		dev_put(bridge);
 		return NF_ACCEPT;
 	}
 	if (in == out) {
 		DEBUG_TRACE("skb: %p, bridge: %p (%s), port bounce on %p (%s)\n", skb, bridge, bridge->name, out, out->name);
 		dev_put(in);
+		dev_put(bridge);
 		return NF_ACCEPT;
 	}
-	if (!compare_ether_addr(skb_eth_hdr->h_source, bridge->dev_addr)) {
+	if (!ecm_mac_addr_equal(skb_eth_hdr->h_source, bridge->dev_addr)) {
 		/*
 		 * Case 2: Routed trafffic would be handled by the INET post routing.
 		 */
 		DEBUG_TRACE("skb: %p, Ignoring routed packet to bridge: %p (%s)\n", skb, bridge, bridge->name);
 		dev_put(in);
+		dev_put(bridge);
 		return NF_ACCEPT;
 	}
 
@@ -7501,6 +7531,7 @@
 	result = ecm_front_end_ipv4_ip_process((struct net_device *)out, in,
 				skb_eth_hdr->h_source, skb_eth_hdr->h_dest, can_accel, false, skb);
 	dev_put(in);
+	dev_put(bridge);
 	return result;
 }
 
@@ -7750,7 +7781,11 @@
 		spin_unlock_bh(&ct->lock);
 	}
 
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
 	acct = nf_conn_acct_find(ct);
+#else
+	acct = nf_conn_acct_find(ct)->counter;
+#endif
 	if (acct) {
 		spin_lock_bh(&ct->lock);
 		atomic64_add(sync->flow_rx_packet_count, &acct[IP_CT_DIR_ORIGINAL].packets);
@@ -7913,7 +7948,7 @@
 static void ecm_front_end_ipv4_conntrack_event_mark(struct nf_conn *ct)
 {
 	struct ecm_db_connection_instance *ci;
-	struct ecm_classifier_instance *cls;
+	struct ecm_classifier_instance *__attribute__((unused))cls;
 
 	DEBUG_INFO("Mark event for ct: %p\n", ct);
 
diff --git a/ecm_front_end_ipv6.c b/ecm_front_end_ipv6.c
index 487cf29..9b9c0dc 100644
--- a/ecm_front_end_ipv6.c
+++ b/ecm_front_end_ipv6.c
@@ -7204,7 +7204,7 @@
 		dev_put(in);
 		return NF_ACCEPT;
 	}
-	if (!compare_ether_addr(skb_eth_hdr->h_source, bridge->dev_addr)) {
+	if (!ecm_mac_addr_equal(skb_eth_hdr->h_source, bridge->dev_addr)) {
 		/*
 		 * Case 2: Routed trafffic would be handled by the INET post routing.
 		 */
diff --git a/ecm_init.c b/ecm_init.c
index bde0c4a..fd16445 100644
--- a/ecm_init.c
+++ b/ecm_init.c
@@ -48,9 +48,11 @@
 extern void ecm_interface_stop(int);
 extern void ecm_interface_exit(void);
 
+#ifdef ECM_INTERFACE_BOND_ENABLE
 extern int ecm_bond_notifier_init(void);
 extern void ecm_bond_notifier_stop(int);
 extern void ecm_bond_notifier_exit(void);
+#endif
 
 extern int ecm_front_end_ipv4_init(void);
 extern void ecm_front_end_ipv4_stop(int);
@@ -66,8 +68,10 @@
 extern void ecm_conntrack_notifier_stop(int);
 extern void ecm_conntrack_notifier_exit(void);
 
+#ifdef ECM_CLASSIFIER_DSCP_ENABLE
 extern int ecm_classifier_dscp_init(void);
 extern void ecm_classifier_dscp_exit(void);
+#endif
 
 /*
  * ecm_init()
@@ -121,20 +125,24 @@
 	}
 #endif
 
+#ifdef ECM_CLASSIFIER_DSCP_ENABLE
 	ret = ecm_classifier_dscp_init();
 	if (0 != ret) {
 		goto err_cls_dscp;
 	}
+#endif
 
 	ret = ecm_interface_init();
 	if (0 != ret) {
 		goto err_iface;
 	}
 
+#ifdef ECM_INTERFACE_BOND_ENABLE
 	ret = ecm_bond_notifier_init();
 	if (0 != ret) {
 		goto err_bond;
 	}
+#endif
 
 	ret = ecm_front_end_ipv4_init();
 	if (0 != ret) {
@@ -163,12 +171,16 @@
 #endif
 	ecm_front_end_ipv4_exit();
 err_fe_ipv4:
+#ifdef ECM_INTERFACE_BOND_ENABLE
 	ecm_bond_notifier_exit();
 err_bond:
+#endif
 	ecm_interface_exit();
 err_iface:
+#ifdef ECM_CLASSIFIER_DSCP_ENABLE
 	ecm_classifier_dscp_exit();
 err_cls_dscp:
+#endif
 #ifdef ECM_CLASSIFIER_HYFI_ENABLE
 	ecm_classifier_hyfi_rules_exit();
 err_cls_hyfi:
@@ -211,8 +223,10 @@
 #endif
 	printk(KERN_INFO "stop interface\n");
 	ecm_interface_stop(1);
+#ifdef ECM_INTERFACE_BOND_ENABLE
 	printk(KERN_INFO "stop bond notifier\n");
 	ecm_bond_notifier_stop(1);
+#endif
 	printk(KERN_INFO "defunct all db connections\n");
 	ecm_db_connection_defunct_all();
 
@@ -225,12 +239,16 @@
 	printk(KERN_INFO "exit front_end_ipv6\n");
 	ecm_front_end_ipv6_exit();
 #endif
+#ifdef ECM_INTERFACE_BOND_ENABLE
 	printk(KERN_INFO "exit bond notifier\n");
 	ecm_bond_notifier_exit();
+#endif
 	printk(KERN_INFO "exit interface\n");
 	ecm_interface_exit();
+#ifdef ECM_CLASSIFIER_DSCP_ENABLE
 	printk(KERN_INFO "exit dscp classifier\n");
 	ecm_classifier_dscp_exit();
+#endif
 #ifdef ECM_CLASSIFIER_HYFI_ENABLE
 	printk(KERN_INFO "exit hyfi classifier\n");
 	ecm_classifier_hyfi_rules_exit();
diff --git a/ecm_interface.c b/ecm_interface.c
index f85cffb..febf03e 100644
--- a/ecm_interface.c
+++ b/ecm_interface.c
@@ -14,6 +14,7 @@
  **************************************************************************
  */
 
+#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
@@ -43,7 +44,9 @@
 
 
 #include <linux/inetdevice.h>
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
 #include <net/ipip.h>
+#endif
 #include <net/ip6_tunnel.h>
 #include <net/addrconf.h>
 #include <linux/if_arp.h>
@@ -116,6 +119,33 @@
 static bool ecm_interface_terminate_pending = false;		/* True when the user has signalled we should quit */
 
 /*
+ * ecm_interface_get_and_hold_dev_master()
+ *	Returns the master device of a net device if any.
+ */
+struct net_device *ecm_interface_get_and_hold_dev_master(struct net_device *dev)
+{
+	struct net_device *master;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3,6,0))
+	rcu_read_lock();
+	master = netdev_master_upper_dev_get_rcu(dev);
+	if (!master) {
+		rcu_read_unlock();
+		return NULL;
+	}
+	dev_hold(master);
+	rcu_read_unlock();
+#else
+	master = dev->master;
+	if (!master) {
+		return NULL;
+	}
+	dev_hold(master);
+#endif
+	return master;
+}
+EXPORT_SYMBOL(ecm_interface_get_and_hold_dev_master);
+
+/*
  * ecm_interface_dev_find_by_local_addr_ipv4()
  *	Return a hold to the device for the given local IP address.  Returns NULL on failure.
  */
@@ -328,12 +358,17 @@
 		return false;
 	}
 	DEBUG_ASSERT(ecm_rt.v4_route, "Did not locate a v4 route!\n");
+	DEBUG_TRACE("Found route\n");
 
 	/*
 	 * Is this destination on link or off-link via a gateway?
 	 */
 	rt = ecm_rt.rt.rtv4;
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
 	if ((rt->rt_dst != rt->rt_gateway) || (rt->rt_flags & RTF_GATEWAY)) {
+#else
+	if (rt->rt_uses_gateway || (rt->rt_flags & RTF_GATEWAY)) {
+#endif
 		*on_link = false;
 		ECM_NIN4_ADDR_TO_IP_ADDR(gw_addr, rt->rt_gateway)
 	} else {
@@ -345,27 +380,35 @@
 	 */
 	rcu_read_lock();
 	dst = ecm_rt.dst;
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
 	neigh = dst_get_neighbour_noref(dst);
 	if (neigh) {
 		neigh_hold(neigh);
-	} else {
+	}
+#else
+	neigh = dst_neigh_lookup(dst, &ipv4_addr);
+#endif
+	if (!neigh) {
 		neigh = neigh_lookup(&arp_tbl, &ipv4_addr, dst->dev);
 	}
 	if (!neigh) {
 		rcu_read_unlock();
 		ecm_interface_route_release(&ecm_rt);
+		DEBUG_WARN("no neigh\n");
 		return false;
 	}
 	if (!(neigh->nud_state & NUD_VALID)) {
 		rcu_read_unlock();
 		neigh_release(neigh);
 		ecm_interface_route_release(&ecm_rt);
+		DEBUG_WARN("neigh nud state is not valid\n");
 		return false;
 	}
 	if (!neigh->dev) {
 		rcu_read_unlock();
 		neigh_release(neigh);
 		ecm_interface_route_release(&ecm_rt);
+		DEBUG_WARN("neigh has no device\n");
 		return false;
 	}
 
@@ -929,6 +972,7 @@
 }
 
 #ifdef CONFIG_IPV6_SIT_6RD
+#ifdef ECM_INTERFACE_SIT_ENABLE
 /*
  * ecm_interface_sit_interface_establish()
  *	Returns a reference to a iface of the SIT type, possibly creating one if necessary.
@@ -979,6 +1023,7 @@
 	return nii;
 }
 #endif
+#endif
 
 /*
  * ecm_interface_tunipip6_interface_establish()
@@ -1192,6 +1237,7 @@
 	}
 
 #ifdef CONFIG_IPV6_SIT_6RD
+#ifdef ECM_INTERFACE_SIT_ENABLE
 	/*
 	 * SIT (6-in-4)?
 	 */
@@ -1226,6 +1272,7 @@
 		return ii;
 	}
 #endif
+#endif
 
 	/*
 	 * IPIP6 Tunnel?
@@ -1685,14 +1732,14 @@
 					DEBUG_TRACE("Net device: %p is BRIDGE, next_dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
 					break;
 				}
-
+#ifdef ECM_INTERFACE_BOND_ENABLE
 				/*
 				 * LAG?
 				 */
 				if (ecm_front_end_is_lag_master(dest_dev)) {
 					/*
 					 * Link aggregation
-					 * Figure out which slave device of the link aggregation will be used to reach the destination.
+					 * Figure out whiich slave device of the link aggregation will be used to reach the destination.
 					 */
 					bool dest_on_link = false;
 					ip_addr_t dest_gw_addr = ECM_IP_ADDR_NULL;
@@ -1712,11 +1759,14 @@
 						memcpy(src_mac_addr, src_node_addr, ETH_ALEN);
 						memcpy(dest_mac_addr, dest_node_addr, ETH_ALEN);
 					} else {
+						struct net_device *dest_dev_master;
+
 						/*
 						 * Use appropriate source MAC address for routed packets
 						 */
-						if (dest_dev->master) {
-							memcpy(src_mac_addr, dest_dev->master->dev_addr, ETH_ALEN);
+						dest_dev_master = ecm_interface_get_and_hold_dev_master(dest_dev);
+						if (dest_dev_master) {
+							memcpy(src_mac_addr, dest_dev_master->dev_addr, ETH_ALEN);
 						} else {
 							memcpy(src_mac_addr, dest_dev->dev_addr, ETH_ALEN);
 						}
@@ -1739,14 +1789,18 @@
 							/*
 							 * find proper interfce from which to issue ARP
 							 */
-							if (dest_dev->master) {
-								master_dev = dest_dev->master;
+							if (dest_dev_master) {
+								master_dev = dest_dev_master;
 							} else {
 								master_dev = dest_dev;
 							}
 
 							dev_hold(master_dev);
 
+							if (dest_dev_master) {
+								dev_put(dest_dev_master);
+							}
+
 							ECM_IP_ADDR_TO_NIN4_ADDR(ipv4_addr, dest_addr);
 							src_ip = inet_select_addr(master_dev, ipv4_addr, RT_SCOPE_LINK);
 							if (!src_ip) {
@@ -1780,6 +1834,10 @@
 							ecm_db_connection_interfaces_deref(interfaces, current_interface_index);
 							return ECM_DB_IFACE_HEIRARCHY_MAX;
 						}
+
+						if (dest_dev_master) {
+							dev_put(dest_dev_master);
+						}
 					}
 
 					next_dev = bond_get_tx_dev(NULL, src_mac_addr, dest_mac_addr,
@@ -1802,6 +1860,7 @@
 					DEBUG_TRACE("Net device: %p is LAG, slave dev: %p (%s)\n", dest_dev, next_dev, next_dev->name);
 					break;
 				}
+#endif
 
 				/*
 				 * ETHERNET!
@@ -2256,7 +2315,11 @@
 		if (!netif_carrier_ok(dev)) {
 			DEBUG_INFO("Net device: %p, CARRIER BAD\n", dev);
 			if (netif_is_bond_slave(dev)) {
-				ecm_interface_dev_regenerate_connections(dev->master);
+				struct net_device *master;
+				master = ecm_interface_get_and_hold_dev_master(dev);
+				DEBUG_ASSERT(master, "Expected a master\n");
+				ecm_interface_dev_regenerate_connections(master);
+				dev_put(master);
 			} else {
 				ecm_interface_dev_regenerate_connections(dev);
 			}
diff --git a/ecm_interface.h b/ecm_interface.h
index 31f9172..d91d88d 100644
--- a/ecm_interface.h
+++ b/ecm_interface.h
@@ -51,3 +51,4 @@
 int32_t ecm_interface_heirarchy_construct(struct ecm_db_iface_instance *interfaces[], ip_addr_t packet_src_addr, ip_addr_t packet_dest_addr, int packet_protocol, struct net_device *given_dest_dev, bool is_routed, struct net_device *given_src_dev, uint8_t *dest_node_addr, uint8_t *src_node_addr);
 void ecm_interface_stats_update(struct ecm_db_connection_instance *ci, uint32_t from_tx_packets, uint32_t from_tx_bytes, uint32_t from_rx_packets, uint32_t from_rx_bytes, uint32_t to_tx_packets, uint32_t to_tx_bytes, uint32_t to_rx_packets, uint32_t to_rx_bytes);
 struct net_device *ecm_interface_dev_find_by_addr(ip_addr_t addr, bool *from_local_addr);
+struct net_device *ecm_interface_get_and_hold_dev_master(struct net_device *dev);
diff --git a/ecm_tracker.c b/ecm_tracker.c
index 5703c14..8c83f78 100644
--- a/ecm_tracker.c
+++ b/ecm_tracker.c
@@ -14,6 +14,7 @@
  **************************************************************************
  */
 
+#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
diff --git a/ecm_tracker_datagram.c b/ecm_tracker_datagram.c
index 641cb79..1996d1e 100644
--- a/ecm_tracker_datagram.c
+++ b/ecm_tracker_datagram.c
@@ -14,6 +14,7 @@
  **************************************************************************
  */
 
+#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
diff --git a/ecm_tracker_udp.c b/ecm_tracker_udp.c
index 5f14362..72edbba 100644
--- a/ecm_tracker_udp.c
+++ b/ecm_tracker_udp.c
@@ -14,6 +14,7 @@
  **************************************************************************
  */
 
+#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
diff --git a/ecm_types.h b/ecm_types.h
index c218269..c5c6d97 100644
--- a/ecm_types.h
+++ b/ecm_types.h
@@ -150,6 +150,7 @@
  */
 #define ECM_IP_ADDR_TO_NIN4_ADDR(nin4, ipaddrt) \
 	{ \
+		nin4 = 0; \
 		ecm_nss_type_check_linux_ipv4(nin4); \
 		ecm_nss_type_check_ecm_ip_addr(ipaddrt); \
 		DEBUG_ASSERT(!ipaddrt[3] && !ipaddrt[2] && (ipaddrt[1] == 0x0000ffff), "Not IPv4 address: " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(ipaddrt)); \
@@ -233,6 +234,19 @@
 	}
 
 /*
+ * ecm_mac_addr_equal()
+ *	Compares two MAC addresses.
+ */
+static inline unsigned ecm_mac_addr_equal(const u8 *addr1, const u8 *addr2)
+{
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
+	return compare_ether_addr(addr1, addr2);
+#else
+	return ether_addr_equal(addr1, addr2);
+#endif
+}
+
+/*
  * ecm_ip_addr_is_non_unicast()
  *	Returns true if the IP address is not unicast
  */