[qca-nss-ecm] Add neigh mac address update notification.

If the mac address of a node changes, destory all the rules
created on that node.

Change-Id: I019094090091a2c5ed563671959122b9066711b5
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
diff --git a/ecm_interface.c b/ecm_interface.c
index a131fc0..d108c66 100644
--- a/ecm_interface.c
+++ b/ecm_interface.c
@@ -5655,6 +5655,68 @@
 EXPORT_SYMBOL(ecm_interface_multicast_find_updates_to_iface_list);
 #endif
 
+#ifdef ECM_DB_XREF_ENABLE
+/*
+ * ecm_interface_neigh_mac_update_notify_event()
+ *	Neighbour mac address change handler.
+ */
+static int ecm_interface_neigh_mac_update_notify_event(struct notifier_block *nb,
+						       unsigned long val,
+						       void *data)
+{
+	struct ecm_db_node_instance *node = NULL;
+	struct neigh_mac_update *nmu = (struct neigh_mac_update *)data;
+
+	/*
+	 * If the old and new mac addresses are equal, do nothing.
+	 * This case shouldn't happen.
+	 */
+	if (!ecm_mac_addr_equal(nmu->old_mac, nmu->update_mac)) {
+		DEBUG_TRACE("old and new mac addresses are equal: %pM\n", nmu->old_mac);
+		return NOTIFY_DONE;
+	}
+
+	/*
+	 * If the old mac is zero, do nothing. When a host joins the arp table first
+	 * time, its old mac comes as zero. We shouldn't handle this case, because
+	 * there is not any connection in ECM db with zero mac.
+	 */
+	if (is_zero_ether_addr(nmu->old_mac)) {
+		DEBUG_WARN("old mac is zero\n");
+		return NOTIFY_DONE;
+	}
+
+	DEBUG_TRACE("old mac: %pM new mac: %pM\n", nmu->old_mac, nmu->update_mac);
+
+	/*
+	 * find node instance corresponding to old mac address
+	 */
+	node = ecm_db_node_find_and_ref((uint8_t *)nmu->old_mac);
+
+	if (unlikely(!node)) {
+		DEBUG_WARN("node address is null\n");
+		return NOTIFY_DONE;
+	}
+	DEBUG_INFO("%p: decelerate the connections for node %pM\n", node, nmu->old_mac);
+	ecm_db_traverse_node_from_connection_list_and_decelerate(node);
+	ecm_db_traverse_node_to_connection_list_and_decelerate(node);
+	ecm_db_traverse_node_from_nat_connection_list_and_decelerate(node);
+	ecm_db_traverse_node_to_nat_connection_list_and_decelerate(node);
+
+	ecm_db_node_deref(node);
+
+	return NOTIFY_DONE;
+}
+
+/*
+ * struct notifier_block ecm_interface_neigh_mac_update_nb
+ *	Registration for neighbour mac address update.
+ */
+static struct notifier_block ecm_interface_neigh_mac_update_nb = {
+	.notifier_call = ecm_interface_neigh_mac_update_notify_event,
+};
+#endif
+
 /*
  * ecm_interface_init()
  */
@@ -5674,6 +5736,9 @@
 	 */
 	br_fdb_update_register_notify(&ecm_interface_node_br_fdb_update_nb);
 #endif
+#ifdef ECM_DB_XREF_ENABLE
+	neigh_mac_update_register_notify(&ecm_interface_neigh_mac_update_nb);
+#endif
 	return 0;
 }
 EXPORT_SYMBOL(ecm_interface_init);
@@ -5690,6 +5755,10 @@
 	spin_unlock_bh(&ecm_interface_lock);
 
 	unregister_netdevice_notifier(&ecm_interface_netdev_notifier);
+#ifdef ECM_DB_XREF_ENABLE
+	neigh_mac_update_unregister_notify(&ecm_interface_neigh_mac_update_nb);
+#endif
+
 #if defined(ECM_DB_XREF_ENABLE) && defined(ECM_BAND_STEERING_ENABLE)
 	/*
 	 * unregister for bridge fdb update events