Merge "[qca-nss-clients] Add source interface update mechanism for capwapmgr"
diff --git a/capwapmgr/nss_capwapmgr.c b/capwapmgr/nss_capwapmgr.c
index 278353d..0067d36 100644
--- a/capwapmgr/nss_capwapmgr.c
+++ b/capwapmgr/nss_capwapmgr.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2020, 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.
@@ -1426,6 +1426,139 @@
 EXPORT_SYMBOL(nss_capwapmgr_update_dest_mac_addr);
 
 /*
+ * nss_capwapmgr_update_src_interface()
+ *	API for updating Source Interface
+ */
+nss_capwapmgr_status_t nss_capwapmgr_update_src_interface(struct net_device *dev, uint8_t tunnel_id, int32_t src_interface_num)
+{
+	struct nss_capwapmgr_priv *priv;
+	struct nss_capwapmgr_tunnel *t;
+	nss_capwapmgr_status_t status;
+	nss_tx_status_t nss_status;
+	uint32_t outer_trustsec_enabled, dtls_enabled, forward_if_num, src_interface_num_temp;
+
+	t = nss_capwapmgr_verify_tunnel_param(dev, tunnel_id);
+	if (!t) {
+		nss_capwapmgr_warn("%p: can't find tunnel: %d\n", dev, tunnel_id);
+		return NSS_CAPWAPMGR_FAILURE_BAD_PARAM;
+	}
+
+	dev_hold(dev);
+	priv = netdev_priv(dev);
+	nss_capwapmgr_info("%p: %d: tunnel update source interface is being called\n", dev, t->if_num);
+	outer_trustsec_enabled = t->capwap_rule.enabled_features & NSS_CAPWAPMGR_FEATURE_OUTER_TRUSTSEC_ENABLED;
+	dtls_enabled = t->capwap_rule.enabled_features & NSS_CAPWAPMGR_FEATURE_DTLS_ENABLED;
+
+	/*
+	 * If trustsec is enabled, just update the next node of trustsec.
+	 */
+	if (outer_trustsec_enabled) {
+		if (!dtls_enabled) {
+			forward_if_num = nss_capwap_ifnum_with_core_id(t->if_num);
+		} else {
+			forward_if_num = nss_dtlsmgr_get_interface(t->dtls_dev, NSS_DTLSMGR_INTERFACE_TYPE_OUTER);
+		}
+
+		nss_status = nss_trustsec_tx_update_nexthop(forward_if_num, src_interface_num, t->capwap_rule.outer_sgt_value);
+		if (nss_status != NSS_TX_SUCCESS) {
+			nss_capwapmgr_warn("%p: unconfigure trustsec_tx failed\n", dev);
+			return NSS_CAPWAPMGR_FAILURE_UNCONFIGURE_TRUSTSEC_TX;
+		}
+
+		if (t->capwap_rule.l3_proto == NSS_CAPWAP_TUNNEL_IPV4) {
+			t->ip_rule.v4.src_interface_num = src_interface_num;
+		} else {
+			t->ip_rule.v6.src_interface_num = src_interface_num;
+		}
+		return NSS_CAPWAPMGR_SUCCESS;
+	}
+
+
+	/*
+	 * Destroy/Re-Create the IPv4/IPv6 rule with the new Interface number for flow and return
+	 */
+	if (t->capwap_rule.l3_proto == NSS_CAPWAP_TUNNEL_IPV4) {
+
+		/*
+		 * Destroy the IP rule only if it already exist.
+		 */
+		if (t->tunnel_state & NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED) {
+			struct nss_ipv4_destroy v4_destroy;
+			v4_destroy.protocol = IPPROTO_UDP;
+			v4_destroy.src_ip = t->ip_rule.v4.src_ip;
+			v4_destroy.dest_ip = t->ip_rule.v4.dest_ip;
+			v4_destroy.src_port = t->ip_rule.v4.src_port;
+			v4_destroy.dest_port = t->ip_rule.v4.dest_port;
+			nss_status = nss_capwapmgr_unconfigure_ipv4_rule(&v4_destroy);
+			if (nss_status != NSS_TX_SUCCESS) {
+				nss_capwapmgr_warn("%p: unconfigure ipv4 rule failed : %d\n", dev, nss_status);
+				dev_put(dev);
+				return NSS_CAPWAPMGR_FAILURE_IP_DESTROY_RULE;
+			}
+
+			t->tunnel_state &= ~NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED;
+		}
+
+		src_interface_num_temp = t->ip_rule.v4.src_interface_num;
+		t->ip_rule.v4.src_interface_num = src_interface_num;
+		nss_capwapmgr_configure_ipv4(&t->ip_rule.v4, 0, 0);
+		if (nss_status != NSS_TX_SUCCESS) {
+			nss_capwapmgr_warn("%p: configure ipv4 rule failed : %d\n", dev, nss_status);
+			t->ip_rule.v4.src_interface_num = src_interface_num_temp;
+			dev_put(dev);
+			return NSS_CAPWAPMGR_FAILURE_IP_RULE;
+		}
+	} else {
+		/*
+		 * Destroy the IP rule only if it already exist.
+		 */
+		if (t->tunnel_state & NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED) {
+			struct nss_ipv6_destroy v6_destroy;
+
+			if (t->capwap_rule.which_udp == NSS_CAPWAP_TUNNEL_UDP) {
+				v6_destroy.protocol = IPPROTO_UDP;
+			} else {
+				v6_destroy.protocol = IPPROTO_UDPLITE;
+			}
+
+			v6_destroy.src_ip[0] = t->ip_rule.v6.src_ip[0];
+			v6_destroy.src_ip[1] = t->ip_rule.v6.src_ip[1];
+			v6_destroy.src_ip[2] = t->ip_rule.v6.src_ip[2];
+			v6_destroy.src_ip[3] = t->ip_rule.v6.src_ip[3];
+
+			v6_destroy.dest_ip[0] = t->ip_rule.v6.dest_ip[0];
+			v6_destroy.dest_ip[1] = t->ip_rule.v6.dest_ip[1];
+			v6_destroy.dest_ip[2] = t->ip_rule.v6.dest_ip[2];
+			v6_destroy.dest_ip[3] = t->ip_rule.v6.dest_ip[3];
+
+			v6_destroy.src_port = t->ip_rule.v6.src_port;
+			v6_destroy.dest_port = t->ip_rule.v6.dest_port;
+			nss_status = nss_capwapmgr_unconfigure_ipv6_rule(&v6_destroy);
+			if (nss_status != NSS_TX_SUCCESS) {
+				nss_capwapmgr_warn("%p: unconfigure ipv6 rule failed : %d\n", dev, nss_status);
+				dev_put(dev);
+				return NSS_CAPWAPMGR_FAILURE_IP_DESTROY_RULE;
+			}
+
+			t->tunnel_state &= ~NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED;
+		}
+
+		src_interface_num_temp = t->ip_rule.v6.src_interface_num;
+		t->ip_rule.v6.src_interface_num = src_interface_num;
+		nss_capwapmgr_configure_ipv6(&t->ip_rule.v6, 0, 0);
+		if (nss_status != NSS_TX_SUCCESS) {
+			nss_capwapmgr_warn("%p: configure ipv6 rule failed : %d\n", dev, nss_status);
+			t->ip_rule.v6.src_interface_num = src_interface_num_temp;
+			dev_put(dev);
+			return NSS_CAPWAPMGR_FAILURE_IP_RULE;
+		}
+	}
+	t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED;
+	return status;
+}
+EXPORT_SYMBOL(nss_capwapmgr_update_src_interface);
+
+/*
  * nss_capwapmgr_dscp_rule_destroy()
  *	API to destroy previously created DSCP rule.
  */
@@ -1877,45 +2010,51 @@
 	 * Recreate ipv4/v6 rules with the new interface number
 	 */
 	if (t->capwap_rule.l3_proto == NSS_CAPWAP_TUNNEL_IPV4) {
-		v4.protocol = IPPROTO_UDP;
-		v4.src_ip = t->ip_rule.v4.src_ip;
-		v4.dest_ip = t->ip_rule.v4.dest_ip;
-		v4.src_port = t->ip_rule.v4.src_port;
-		v4.dest_port = t->ip_rule.v4.dest_port;
-		nss_status = nss_capwapmgr_unconfigure_ipv4_rule(&v4);
-		if (nss_status != NSS_TX_SUCCESS) {
-			nss_capwapmgr_warn("%p: unconfigure ipv4 rule failed : %d\n", dev, nss_status);
-			dev_put(dev);
-			return NSS_CAPWAPMGR_FAILURE_IP_DESTROY_RULE;
+		if (t->tunnel_state & NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED) {
+			v4.protocol = IPPROTO_UDP;
+			v4.src_ip = t->ip_rule.v4.src_ip;
+			v4.dest_ip = t->ip_rule.v4.dest_ip;
+			v4.src_port = t->ip_rule.v4.src_port;
+			v4.dest_port = t->ip_rule.v4.dest_port;
+			nss_status = nss_capwapmgr_unconfigure_ipv4_rule(&v4);
+			if (nss_status != NSS_TX_SUCCESS) {
+				nss_capwapmgr_warn("%p: unconfigure ipv4 rule failed : %d\n", dev, nss_status);
+				dev_put(dev);
+				return NSS_CAPWAPMGR_FAILURE_IP_DESTROY_RULE;
+			}
+			t->tunnel_state &= ~NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED;
 		}
+
 		t->ip_rule.v4.dest_interface_num = ip_if_num;
 		nss_status = nss_capwapmgr_configure_ipv4(&t->ip_rule.v4, 0, 0);
 	} else {
-		if (t->capwap_rule.which_udp == NSS_CAPWAP_TUNNEL_UDP) {
-			v6.protocol = IPPROTO_UDP;
-		} else {
-			v6.protocol = IPPROTO_UDPLITE;
+		if (t->tunnel_state & NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED) {
+			if (t->capwap_rule.which_udp == NSS_CAPWAP_TUNNEL_UDP) {
+				v6.protocol = IPPROTO_UDP;
+			} else {
+				v6.protocol = IPPROTO_UDPLITE;
+			}
+
+			v6.src_ip[0] = t->ip_rule.v6.src_ip[0];
+			v6.src_ip[1] = t->ip_rule.v6.src_ip[1];
+			v6.src_ip[2] = t->ip_rule.v6.src_ip[2];
+			v6.src_ip[3] = t->ip_rule.v6.src_ip[3];
+
+			v6.dest_ip[0] = t->ip_rule.v6.dest_ip[0];
+			v6.dest_ip[1] = t->ip_rule.v6.dest_ip[1];
+			v6.dest_ip[2] = t->ip_rule.v6.dest_ip[2];
+			v6.dest_ip[3] = t->ip_rule.v6.dest_ip[3];
+
+			v6.src_port = t->ip_rule.v6.src_port;
+			v6.dest_port = t->ip_rule.v6.dest_port;
+			nss_status = nss_capwapmgr_unconfigure_ipv6_rule(&v6);
+			if (nss_status != NSS_TX_SUCCESS) {
+				nss_capwapmgr_warn("%p: unconfigure ipv6 rule failed : %d\n", dev, nss_status);
+				dev_put(dev);
+				return NSS_CAPWAPMGR_FAILURE_IP_DESTROY_RULE;
+			}
+			t->tunnel_state &= ~NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED;
 		}
-
-		v6.src_ip[0] = t->ip_rule.v6.src_ip[0];
-		v6.src_ip[1] = t->ip_rule.v6.src_ip[1];
-		v6.src_ip[2] = t->ip_rule.v6.src_ip[2];
-		v6.src_ip[3] = t->ip_rule.v6.src_ip[3];
-
-		v6.dest_ip[0] = t->ip_rule.v6.dest_ip[0];
-		v6.dest_ip[1] = t->ip_rule.v6.dest_ip[1];
-		v6.dest_ip[2] = t->ip_rule.v6.dest_ip[2];
-		v6.dest_ip[3] = t->ip_rule.v6.dest_ip[3];
-
-		v6.src_port = t->ip_rule.v6.src_port;
-		v6.dest_port = t->ip_rule.v6.dest_port;
-		nss_status = nss_capwapmgr_unconfigure_ipv6_rule(&v6);
-		if (nss_status != NSS_TX_SUCCESS) {
-			nss_capwapmgr_warn("%p: unconfigure ipv6 rule failed : %d\n", dev, nss_status);
-			dev_put(dev);
-			return NSS_CAPWAPMGR_FAILURE_IP_DESTROY_RULE;
-		}
-
 		t->ip_rule.v6.dest_interface_num = ip_if_num;
 		nss_status = nss_capwapmgr_configure_ipv6(&t->ip_rule.v6, 0, 0);
 	}
@@ -1929,6 +2068,7 @@
 	/*
 	 * Now configure capwap dtls
 	 */
+	t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED;
 	status = nss_capwapmgr_tx_msg_sync(priv->nss_ctx, dev, &capwapmsg);
 	if (status != NSS_CAPWAPMGR_SUCCESS) {
 		nss_capwapmgr_warn("%p: configure DTLS failed : %d\n", dev, status);
@@ -2412,6 +2552,7 @@
 	t->if_num = capwap_if_num;
 	priv->if_num_to_tunnel_id[capwap_if_num] = tunnel_id;
 	t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_CONFIGURED;
+	t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED;
 
 	dev_put(dev);
 	return status;
@@ -2553,42 +2694,44 @@
 	/*
 	 * Destroy IP rule first.
 	 */
-	if (t->capwap_rule.l3_proto == NSS_CAPWAP_TUNNEL_IPV4) {
-		memset(&v4, 0, sizeof (struct nss_ipv4_destroy));
-		v4.protocol = IPPROTO_UDP;
-		v4.src_ip = t->ip_rule.v4.src_ip;
-		v4.dest_ip = t->ip_rule.v4.dest_ip;
-		v4.src_port = t->ip_rule.v4.src_port;
-		v4.dest_port = t->ip_rule.v4.dest_port;
-		nss_status = nss_capwapmgr_unconfigure_ipv4_rule(&v4);
-	} else {
-		memset(&v6, 0, sizeof (struct nss_ipv6_destroy));
-		if (t->capwap_rule.which_udp == NSS_CAPWAP_TUNNEL_UDP) {
-			v6.protocol = IPPROTO_UDP;
+	if (t->tunnel_state & NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED) {
+		if (t->capwap_rule.l3_proto == NSS_CAPWAP_TUNNEL_IPV4) {
+			memset(&v4, 0, sizeof (struct nss_ipv4_destroy));
+			v4.protocol = IPPROTO_UDP;
+			v4.src_ip = t->ip_rule.v4.src_ip;
+			v4.dest_ip = t->ip_rule.v4.dest_ip;
+			v4.src_port = t->ip_rule.v4.src_port;
+			v4.dest_port = t->ip_rule.v4.dest_port;
+			nss_status = nss_capwapmgr_unconfigure_ipv4_rule(&v4);
 		} else {
-			v6.protocol = IPPROTO_UDPLITE;
+			memset(&v6, 0, sizeof (struct nss_ipv6_destroy));
+			if (t->capwap_rule.which_udp == NSS_CAPWAP_TUNNEL_UDP) {
+				v6.protocol = IPPROTO_UDP;
+			} else {
+				v6.protocol = IPPROTO_UDPLITE;
+			}
+
+			v6.src_ip[0] = t->ip_rule.v6.src_ip[0];
+			v6.src_ip[1] = t->ip_rule.v6.src_ip[1];
+			v6.src_ip[2] = t->ip_rule.v6.src_ip[2];
+			v6.src_ip[3] = t->ip_rule.v6.src_ip[3];
+
+			v6.dest_ip[0] = t->ip_rule.v6.dest_ip[0];
+			v6.dest_ip[1] = t->ip_rule.v6.dest_ip[1];
+			v6.dest_ip[2] = t->ip_rule.v6.dest_ip[2];
+			v6.dest_ip[3] = t->ip_rule.v6.dest_ip[3];
+
+			v6.src_port = t->ip_rule.v6.src_port;
+			v6.dest_port = t->ip_rule.v6.dest_port;
+			nss_status = nss_capwapmgr_unconfigure_ipv6_rule(&v6);
 		}
 
-		v6.src_ip[0] = t->ip_rule.v6.src_ip[0];
-
-		v6.src_ip[1] = t->ip_rule.v6.src_ip[1];
-		v6.src_ip[2] = t->ip_rule.v6.src_ip[2];
-		v6.src_ip[3] = t->ip_rule.v6.src_ip[3];
-
-		v6.dest_ip[0] = t->ip_rule.v6.dest_ip[0];
-		v6.dest_ip[1] = t->ip_rule.v6.dest_ip[1];
-		v6.dest_ip[2] = t->ip_rule.v6.dest_ip[2];
-		v6.dest_ip[3] = t->ip_rule.v6.dest_ip[3];
-
-		v6.src_port = t->ip_rule.v6.src_port;
-		v6.dest_port = t->ip_rule.v6.dest_port;
-		nss_status = nss_capwapmgr_unconfigure_ipv6_rule(&v6);
-	}
-
-	if (nss_status != NSS_TX_SUCCESS) {
-		nss_capwapmgr_warn("%p: %d: Unconfigure IP rule failed for tunnel : %d\n",
-			dev, if_num, tunnel_id);
-		return NSS_CAPWAPMGR_FAILURE_IP_DESTROY_RULE;
+		if (nss_status != NSS_TX_SUCCESS) {
+			nss_capwapmgr_warn("%p: %d: Unconfigure IP rule failed for tunnel : %d\n",
+				dev, if_num, tunnel_id);
+			return NSS_CAPWAPMGR_FAILURE_IP_DESTROY_RULE;
+		}
+		t->tunnel_state &= ~NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED;
 	}
 
 	/*
@@ -2600,9 +2743,16 @@
 			dev, if_num, tunnel_id);
 
 		if (t->capwap_rule.l3_proto == NSS_CAPWAP_TUNNEL_IPV4) {
-			nss_capwapmgr_configure_ipv4(&t->ip_rule.v4, 0, 0);
+			nss_status = nss_capwapmgr_configure_ipv4(&t->ip_rule.v4, 0, 0);
+			if (nss_status == NSS_TX_SUCCESS) {
+				t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED;
+			}
+
 		} else {
-			nss_capwapmgr_configure_ipv6(&t->ip_rule.v6, 0, 0);
+			nss_status = nss_capwapmgr_configure_ipv6(&t->ip_rule.v6, 0, 0);
+			if (nss_status == NSS_TX_SUCCESS) {
+				t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED;
+			}
 		}
 
 		return NSS_CAPWAPMGR_FAILURE_CAPWAP_DESTROY_RULE;
diff --git a/exports/nss_capwapmgr.h b/exports/nss_capwapmgr.h
index 4b41f8b..256c03f 100644
--- a/exports/nss_capwapmgr.h
+++ b/exports/nss_capwapmgr.h
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2020, 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.
@@ -28,10 +28,12 @@
  */
 #define NSS_CAPWAPMGR_MAX_TUNNELS		32
 
-#define NSS_CAPWAPMGR_TUNNEL_STATE_CONFIGURED	0x1
+#define NSS_CAPWAPMGR_TUNNEL_STATE_CONFIGURED		0x1
 					/**< Bit is set if tunnel has been configured */
-#define NSS_CAPWAPMGR_TUNNEL_STATE_ENABLED	0x2
+#define NSS_CAPWAPMGR_TUNNEL_STATE_ENABLED		0x2
 					/**< Bit is set if tunnel has been enabled */
+#define NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED	0x4
+					/**< Bit is set if tunnel IP rule exist */
 
 /*
  * Tunnel feature flags
@@ -212,6 +214,17 @@
 nss_capwapmgr_status_t nss_capwapmgr_update_dest_mac_addr(struct net_device *dev, uint8_t tunnel_id, uint8_t *mac_addr);
 
 /**
+ * @brief Updates Source Interface number
+ *
+ * @param netdevice
+ * @param tunnel_id
+ * @param source interface number
+ *
+ * @return nss_capwapmgr_status_t
+ */
+extern nss_capwapmgr_status_t nss_capwapmgr_update_src_interface(struct net_device *dev, uint8_t tunnel_id, int32_t src_interface_num);
+
+/**
  * @brief Delete a DSCP prioritization rule that was created.
  *
  * @param Rule ID