[qca-nss-clients] Changes in GRE to enable eogre Configuration.

Added fields in cfg struct to enable custom next dev in both direction.
Added code to configure custom next dev in outer direction.

Change-Id: I70748c232e6ae1a87f98382f32caa91fc5703155
Signed-off-by: Suruchi Suman <surusuma@codeaurora.org>
diff --git a/gre/nss_connmgr_gre_public.h b/exports/nss_connmgr_gre_public.h
similarity index 75%
rename from gre/nss_connmgr_gre_public.h
rename to exports/nss_connmgr_gre_public.h
index 62fdd47..dcdeb37 100644
--- a/gre/nss_connmgr_gre_public.h
+++ b/exports/nss_connmgr_gre_public.h
@@ -17,6 +17,8 @@
 #ifndef _NSS_CONNMGR_GRE_PUBLIC_H_
 #define _NSS_CONNMGR_GRE_PUBLIC_H_
 
+#include "nss_dynamic_interface.h"
+
 /**
  * @brief tap/tun enums
  *
@@ -79,34 +81,40 @@
  *
  * User of this client driver needs to fill in this structure and call
  * nss_connmgr_gre_create_interface() API to create GRE tap interface.
- * There is no support for Keys, Sequence number and checksum.
+ * There is no support for Sequence number and checksum.
  */
 struct nss_connmgr_gre_cfg {
-	enum nss_connmgr_gre_mode mode;		/**< GRE modes. (Mandatory Field) */
+	enum nss_connmgr_gre_mode mode;		/**< GRE modes. (Mandatory field) */
 	enum nss_connmgr_gre_ip_type ip_type;	/**< IP types (Mandatory field) */
 
 	bool set_df;				/**< Set DF flag ? (Optional field) */
-	bool ikey_valid, okey_valid;		/**< Take care of keys ? (No support) */
-	bool iseq_valid, oseq_valid;		/**< Take care of sequence number ? (No support) */
+	bool ikey_valid, okey_valid;		/**< Take care of keys ? (Optional field)*/
+	bool iseq_valid, oseq_valid;		/**< Take care of sequence number ? (No support)*/
 	bool icsum_valid, ocsum_valid;		/**< Take care of checksum ? (No support)*/
 	bool tos_inherit;			/**< Inherit TOS ? (Optional) */
 	bool ttl_inherit;			/**< Interit TTL ? (Optional) */
-	bool use_mac_hdr;			/**< Add MAC header which is provided (Optional Field)*/
-	bool add_padding;			/**< Add padding to make GRE 4 byte aligned ? (Optional Field) */
-	bool copy_metadata;			/**< Copy metadata during alignment ? (Optional Field) */
-	bool is_ipv6;				/**< Set if addr is IPv6 (Mandatory Field)*/
+	bool dscp_valid;			/**< Is DSCP provided per packet? (Optional) */
+	bool use_mac_hdr;			/**< Add MAC header which is provided (Optional field)*/
+	bool add_padding;			/**< Add padding to make GRE 4 byte aligned ? (Optional field) */
+	bool copy_metadata;			/**< Copy metadata during alignment ? (Optional field) */
+	bool is_ipv6;				/**< Set if addr is IPv6 (Mandatory field)*/
 
-	uint32_t src_ip[4];			/**< Src IP address (Mandatory Field) */
-	uint32_t dest_ip[4];			/**< Dest IP address (Mandatory Field)*/
+	uint32_t src_ip[4];			/**< Src IP address (Mandatory field) */
+	uint32_t dest_ip[4];			/**< Dest IP address (Mandatory field)*/
 
 	uint16_t src_mac[3];			/**< Src MAC address (Depends on use_mac_hdr field) */
 	uint16_t dest_mac[3];			/**< Dest MAC address (Depends on use_mac_hdr field) */
 
-	uint32_t ikey;				/**< In Key (No support) */
-	uint32_t okey;				/**< Out Key (No support) */
+	uint32_t ikey;				/**< In Key (Optional field)*/
+	uint32_t okey;				/**< Out Key (Optional field)*/
 
-	struct net_device *next_dev;		/**< Next hop netdevice (Mandatory Field) */
-	char *name;				/**< Name of GRE Tap interface (Optional Field) */
+	struct net_device *next_dev;		/**< Next network device inner flow (Mandatory field)*/
+	enum nss_dynamic_interface_type inner_nss_if_type;	/**< Dynamic interface type of inner network device */
+
+	struct net_device *next_dev_outer;	/**< Next network device outer flow (Mandatory field)*/
+	enum nss_dynamic_interface_type outer_nss_if_type;	/**< Dynamic interface type of outer network device */
+
+	char *name;				/**< Name of GRE Tap interface (Optional field) */
 
 	uint8_t ttl;				/**< Time to Live (Depends on ttl_inherit field) */
 	uint8_t tos;				/**< Type of service (Depends on tos_inherit field) */
@@ -119,7 +127,23 @@
  * API to create/delete GRE interface. These API should not
  * be invoked in interrupt/softirq context
  */
-struct net_device *nss_connmgr_gre_create_interface(struct nss_connmgr_gre_cfg *cfg, enum nss_connmgr_gre_err_codes *err_code);
+struct net_device *nss_connmgr_gre_create_interface(
+		struct nss_connmgr_gre_cfg *cfg, enum nss_connmgr_gre_err_codes *err_code);
+
 enum nss_connmgr_gre_err_codes nss_connmgr_gre_destroy_interface(struct net_device *dev);
 
+/**
+ * @brief GRE interface Open API
+ *
+ * API to enable GRE interface.
+ */
+extern int nss_connmgr_gre_dev_open(struct net_device *dev);
+
+/**
+ * @brief GRE interface Close API
+ *
+ * API to disable GRE interface.
+ */
+extern int nss_connmgr_gre_dev_close(struct net_device *dev);
+
 #endif
diff --git a/gre/nss_connmgr_gre.c b/gre/nss_connmgr_gre.c
index c685544..5e32b61 100644
--- a/gre/nss_connmgr_gre.c
+++ b/gre/nss_connmgr_gre.c
@@ -33,7 +33,7 @@
 
 #include <nss_api_if.h>
 #include <nss_dynamic_interface.h>
-
+#include <nss_cmn.h>
 #include "nss_connmgr_gre_public.h"
 #include "nss_connmgr_gre.h"
 
@@ -225,7 +225,7 @@
 	struct nss_ctx_instance *gre_ctx;
 	nss_connmgr_gre_priv_t *priv = netdev_priv(dev);
 
-	if_number = priv->nss_if_number;
+	if_number = priv->nss_if_number_inner;
 	if (unlikely(if_number <= 0)) {
 		nss_connmgr_gre_info("%p: GRE dev is not registered with nss\n", dev);
 		goto fail;
@@ -305,7 +305,7 @@
  * nss_connmgr_gre_dev_open()
  *	Netdev ops function to open netdevice.
  */
-static int nss_connmgr_gre_dev_open(struct net_device *dev)
+int nss_connmgr_gre_dev_open(struct net_device *dev)
 {
 	struct nss_ctx_instance *nss_ctx;
 	struct nss_gre_msg req;
@@ -361,12 +361,13 @@
 	netif_start_queue(dev);
 	return 0;
 }
+EXPORT_SYMBOL(nss_connmgr_gre_dev_open);
 
 /*
  * nss_connmgr_gre_dev_close()
  *	Netdevice ops function to close netdevice.
  */
-static int nss_connmgr_gre_dev_close(struct net_device *dev)
+int nss_connmgr_gre_dev_close(struct net_device *dev)
 {
 	struct nss_ctx_instance *nss_ctx;
 	struct nss_gre_msg req;
@@ -425,6 +426,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(nss_connmgr_gre_dev_close);
 
 /*
  * Tap net device ops
@@ -720,7 +722,8 @@
 {
 	struct nss_ctx_instance *nss_ctx;
 	struct net_device *dev = NULL;
-	struct net_device *next_dev = NULL;
+	struct net_device *next_dev_inner = NULL;
+	struct net_device *next_dev_outer = NULL;
 	struct nss_gre_iface_instance *ngii;
 	struct nss_gre_msg req;
 	struct nss_gre_config_msg *cmsg = &req.msg.cmsg;
@@ -729,7 +732,7 @@
 	uint32_t features = 0;
 	int32_t inner_if, outer_if;
 	char name[IFNAMSIZ] = {0};
-	int ret = -1, retry;
+	int ret = -1, retry, next_if_num_inner = 0, next_if_num_outer = 0;
 
 	if (cfg->name) {
 		strlcpy(name, cfg->name, IFNAMSIZ);
@@ -801,7 +804,7 @@
 	 * Create config cmd for acceleration engine
 	 */
 	memset(&req, 0, sizeof(struct nss_gre_msg));
-	ret = nss_connmgr_gre_prepare_config_cmd(dev, &req, &next_dev, true);
+	ret = nss_connmgr_gre_prepare_config_cmd(dev, &req, &next_dev_inner, true);
 	if (ret) {
 		nss_connmgr_gre_warning("%p: gre get config failed\n", dev);
 		*err_code = ret;
@@ -818,6 +821,14 @@
 	}
 
 	/*
+	 * Ignore set MAC flag for EoGRE
+	 * TODO: Find a better way to clear this flag
+	 */
+	if (cfg->next_dev_outer) {
+		cmsg->flags &= ~NSS_GRE_CONFIG_SET_MAC;
+	}
+
+	/*
 	 * By now, we should have valid MAC addresses
 	 */
 	if (!is_valid_ether_addr((const u8 *)cmsg->src_mac) ||
@@ -827,27 +838,91 @@
 		goto release_ref;
 	}
 
+	/*
+	 * Configure the inner nexthop ifnum
+	 */
 	if (cfg->next_dev) {
-
-		if (next_dev) {
-			dev_put(next_dev);
+		/*
+		 * Release hold on GRE inner's nexthop that we have found,
+		 * since it has been passed explicitly via the cfg
+		 */
+		if (next_dev_inner) {
+			dev_put(next_dev_inner);
 		}
 
 		dev_hold(cfg->next_dev);
-		cmsg->next_node_if_num = nss_cmn_get_interface_number_by_dev(cfg->next_dev);
-		next_dev = cfg->next_dev;
 
-		if (cmsg->next_node_if_num < 0) {
-			nss_connmgr_gre_warning("%p: Next dev = %s is not registered with ae engine\n",
+		/*
+		 * TODO: Use the dynamic interface type for the inner's nexthop, in addition to the next_dev.
+		 */
+		next_if_num_inner = nss_cmn_get_interface_number_by_dev(cfg->next_dev);
+		next_dev_inner = cfg->next_dev;
+		if (next_if_num_inner < 0) {
+			nss_connmgr_gre_warning("%p: Next dev inner device= %s is not registered with ae engine\n",
 						dev, cfg->next_dev->name);
 			*err_code = GRE_ERR_NEXT_NODE_UNREG_IN_AE;
 			goto release_ref;
 		}
+
 		cmsg->flags |= NSS_GRE_CONFIG_NEXT_NODE_AVAILABLE;
 	}
 
 	/*
-	 * By now, we should have a valid next node
+	 * Configure the outer nexthop ifnum
+	 */
+	if (cfg->next_dev_outer) {
+		dev_hold(cfg->next_dev_outer);
+
+		/*
+		 * Verify if dynamic interface type is in range.
+		 */
+		if (cfg->outer_nss_if_type >= NSS_DYNAMIC_INTERFACE_TYPE_MAX) {
+			nss_connmgr_gre_warning("%p: invalid cfg, outer nexthop type %d is not in range\n",
+				       dev, cfg->outer_nss_if_type);
+			goto release_ref;
+		}
+
+		next_if_num_outer = nss_cmn_get_interface_number_by_dev_and_type(cfg->next_dev_outer, cfg->outer_nss_if_type);
+		next_dev_outer = cfg->next_dev_outer;
+
+		if (next_if_num_outer < 0) {
+			nss_connmgr_gre_warning("%p: Next dev outer device %s with dynamic if num %d not registered with NSS\n",
+					dev, cfg->next_dev_outer->name, next_if_num_outer);
+			*err_code = GRE_ERR_NEXT_NODE_UNREG_IN_AE;
+			goto release_ref;
+		}
+
+		/*
+		 * Get the NSS ctx for the outer next hop
+		 */
+		nss_ctx = nss_dynamic_interface_get_nss_ctx_by_type(cfg->outer_nss_if_type);
+		if (!nss_ctx) {
+			nss_connmgr_gre_warning("Could not get NSS context for type : %d\n", cfg->outer_nss_if_type);
+			goto release_ref;
+		}
+
+		/*
+		 * Append the core-id for the outer next hop ifnum
+		 */
+		next_if_num_outer = nss_cmn_append_core_id(nss_ctx, next_if_num_outer);
+		if (!next_if_num_outer) {
+			nss_connmgr_gre_warning("%p: Could not get interface number with core ID for outer nexthop device %s with core ID.\n",
+				       nss_ctx, next_dev_outer->name);
+			goto release_ref;
+		}
+
+		/*
+		 * Set per packet DSCP configuration if needed
+		 */
+		if (cfg->dscp_valid) {
+			cmsg->flags |= NSS_GRE_CONFIG_DSCP_VALID;
+		}
+
+		cmsg->flags |= NSS_GRE_CONFIG_NEXT_NODE_AVAILABLE;
+	}
+
+	/*
+	 * By now, we should have a valid next node for either inner or outer
 	 */
 	if (!(cmsg->flags & NSS_GRE_CONFIG_NEXT_NODE_AVAILABLE)) {
 		nss_connmgr_gre_warning("%p: Next dev is not available\n", dev);
@@ -895,6 +970,8 @@
 	}
 
 	ngii->outer_ifnum = outer_if;
+	priv = (nss_connmgr_gre_priv_t *)netdev_priv(dev);
+	priv->next_dev_outer = next_dev_outer;
 
 	/*
 	 * Create nss inner dynamic interface
@@ -907,9 +984,8 @@
 	}
 
 	ngii->inner_ifnum = inner_if;
-	priv = (nss_connmgr_gre_priv_t *)netdev_priv(dev);
-	priv->nss_if_number = inner_if;
-	priv->next_dev = next_dev;
+	priv->next_dev_inner = next_dev_inner;
+	priv->nss_if_number_inner = inner_if;
 
 	/*
 	 * Register outer gre tunnel with NSS
@@ -946,33 +1022,56 @@
 	/*
 	 * Send encap config to AE
 	 */
+	cmsg->flags &= ~NSS_GRE_CONFIG_NEXT_NODE_AVAILABLE;
+
+	/*
+	 * Configure nexthop to inner node if available
+	 */
+	if (next_if_num_inner) {
+		cmsg->next_node_if_num = next_if_num_inner;
+		cmsg->flags |= NSS_GRE_CONFIG_NEXT_NODE_AVAILABLE;
+	}
 	cmsg->sibling_if_num = outer_if;
 	nss_gre_msg_init(&req, inner_if, NSS_GRE_MSG_ENCAP_CONFIGURE, sizeof(struct nss_gre_config_msg), NULL, NULL);
 	status = nss_gre_tx_msg_sync(nss_ctx, &req);
 	if (status != NSS_TX_SUCCESS) {
 		*err_code = GRE_ERR_AE_CONFIG_FAILED;
+		nss_connmgr_gre_info("%p: Send Encap config to AE failed\n", next_dev_inner);
 		goto unregister_nss_interface;
 	}
 
 	/*
 	 * Send decap config to AE
 	 */
+	cmsg->flags &= ~NSS_GRE_CONFIG_NEXT_NODE_AVAILABLE;
+
+	/*
+	 * Configure nexthop to outer node if available
+	 */
+	if (next_if_num_outer) {
+		cmsg->next_node_if_num = next_if_num_outer;
+		cmsg->flags |= NSS_GRE_CONFIG_NEXT_NODE_AVAILABLE;
+	}
 	cmsg->sibling_if_num = inner_if;
 	nss_gre_msg_init(&req, outer_if, NSS_GRE_MSG_DECAP_CONFIGURE, sizeof(struct nss_gre_config_msg), NULL, NULL);
 	status = nss_gre_tx_msg_sync(nss_ctx, &req);
 	if (status != NSS_TX_SUCCESS) {
 		*err_code = GRE_ERR_AE_CONFIG_FAILED;
+		nss_connmgr_gre_info("%p: Send decap config to AE failed\n", next_dev_outer);
 		goto unregister_nss_interface;
 	}
 
 	/*
-	 * Set vap next hop
+	 * Set vap next hop if next_dev is configured
+	 * TODO: Do this in a more generic manner by checking the dynamic interface type of next_dev
 	 */
-	ret = nss_connmgr_gre_set_wifi_next_hop(cfg->next_dev);
-	if (ret) {
-		nss_connmgr_gre_info("%p: Setting next hop of wifi vdev failed\n", dev);
-		*err_code = ret;
-		goto unregister_nss_interface;
+	if (cfg->next_dev) {
+		ret = nss_connmgr_gre_set_wifi_next_hop(cfg->next_dev);
+		if (ret) {
+			nss_connmgr_gre_info("%p: Setting next hop of wifi vdev failed\n", dev);
+			*err_code = ret;
+			goto unregister_nss_interface;
+		}
 	}
 
 	memcpy(&ngii->gre_cfg, cfg, sizeof(*cfg));
@@ -1019,8 +1118,12 @@
 	unregister_netdevice(dev);
 
 release_ref:
-	if (next_dev) {
-		dev_put(next_dev);
+	if (next_dev_inner) {
+		dev_put(next_dev_inner);
+	}
+
+	if (next_dev_outer) {
+		dev_put(next_dev_outer);
 	}
 
 	return dev;
@@ -1145,7 +1248,13 @@
 	 * Decrement ref to next_dev
 	 */
 	priv = (nss_connmgr_gre_priv_t *)netdev_priv(dev);
-	dev_put(priv->next_dev);
+	if (priv->next_dev_inner) {
+		dev_put(priv->next_dev_inner);
+	}
+
+	if (priv->next_dev_outer) {
+		dev_put(priv->next_dev_outer);
+	}
 
 	ret = nss_connmgr_gre_destroy_inner_interface(dev, ngii->inner_ifnum);
 	if (ret != GRE_SUCCESS) {
@@ -1169,12 +1278,14 @@
 
 /*
  * nss_connmgr_gre_validate_config()
- *	No support for KEY, CSUM, SEQ number
+ *	No support for CSUM, SEQ number.
  */
 static bool nss_connmgr_gre_validate_config(struct nss_connmgr_gre_cfg *cfg)
 {
-	if (cfg->ikey_valid || cfg->okey_valid || cfg->iseq_valid ||
-	    cfg->oseq_valid || cfg->icsum_valid || cfg->ocsum_valid) {
+	/*
+	 * TODO:Disallow key for standard GRE TAP/TUN.
+	 */
+	if (cfg->iseq_valid || cfg->oseq_valid || cfg->icsum_valid || cfg->ocsum_valid) {
 		return false;
 	}
 
@@ -1635,10 +1746,10 @@
 	return gre_flags;
 }
 
-/*
- *  nss_connmgr_gre_destroy_interface()
- *	User API to delete interface
- */
+ /*
+  * nss_connmgr_gre_destroy_interface()
+  *	User API to delete interface
+  */
 enum nss_connmgr_gre_err_codes nss_connmgr_gre_destroy_interface(struct net_device *dev)
 {
 	enum nss_connmgr_gre_err_codes ret;
@@ -1689,7 +1800,7 @@
 	}
 
 	if (!nss_connmgr_gre_validate_config(cfg)) {
-		nss_connmgr_gre_info("No support for Key/Csum/Sequence number\n");
+		nss_connmgr_gre_info("No support for Csum/Sequence number\n");
 		*err_code = GRE_ERR_UNSUPPORTED_CFG;
 		return NULL;
 	}
diff --git a/gre/nss_connmgr_gre.h b/gre/nss_connmgr_gre.h
index 6cec58c..d426bd0 100644
--- a/gre/nss_connmgr_gre.h
+++ b/gre/nss_connmgr_gre.h
@@ -23,6 +23,8 @@
 #ifndef _NSS_CONNMGR_GRE_H_
 #define _NSS_CONNMGR_GRE_H_
 
+#include "nss_connmgr_gre_public.h"
+
 /*
  * GRE debug macros
  */
diff --git a/gre/nss_connmgr_gre_v6.c b/gre/nss_connmgr_gre_v6.c
index f9a8e58..8c399e8 100644
--- a/gre/nss_connmgr_gre_v6.c
+++ b/gre/nss_connmgr_gre_v6.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019 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.
@@ -72,15 +72,16 @@
 {
 	struct neighbour *neigh;
 	struct rt6_info *rt;
-	struct dst_entry *dst;
-	struct in6_addr ipv6_addr;
+	struct in6_addr src_addr, dst_addr, mc_dst_addr;
 	struct net_device *local_dev;
 
+	memcpy(src_addr.s6_addr, src_ip, 16);
+	memcpy(dst_addr.s6_addr, dest_ip, 16);
+
 	/*
 	 * Find src MAC address
 	 */
-	memcpy(ipv6_addr.s6_addr, src_ip, 16);
-	local_dev = (struct net_device *)ipv6_dev_find(&init_net, &ipv6_addr, 1);
+	local_dev = (struct net_device *)ipv6_dev_find(&init_net, &src_addr, 1);
 	if (!local_dev) {
 		nss_connmgr_gre_warning("Unable to find local dev for %pI6", src_ip);
 		return GRE_ERR_NO_LOCAL_NETDEV;
@@ -91,27 +92,55 @@
 	/*
 	 * Find dest MAC address
 	 */
-	memcpy(ipv6_addr.s6_addr, dest_ip, 16);
-	rt = rt6_lookup(&init_net, &ipv6_addr, NULL, 0, 0);
+	rt = rt6_lookup(&init_net, &dst_addr, NULL, 0, 0);
 	if (!rt) {
+		nss_connmgr_gre_warning("Unable to find route lookup for %pI6", dest_ip);
 		return GRE_ERR_NEIGH_LOOKUP;
 	}
-	dst = (struct dst_entry *)rt;
-	neigh = dst_neigh_lookup(dst, &ipv6_addr);
 
-	if (!neigh) {
-		neigh = neigh_lookup(&nd_tbl, (const void *)&ipv6_addr,  rt->dst.dev);
-	}
-
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
+	neigh = rt->dst.ops->neigh_lookup(&rt->dst, &dst_addr);
+#else
+	neigh = rt->dst.ops->neigh_lookup(&rt->dst, NULL, &dst_addr);
+#endif
 	if (neigh && !is_valid_ether_addr(neigh->ha)) {
 		neigh_release(neigh);
 		neigh = NULL;
 	}
 
 	if (!neigh) {
+
+		/*
+		 * Issue a Neighbour soliciation request
+	 	*/
+		nss_connmgr_gre_info("Issue Neighbour solicitation request\n");
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0))
+		ndisc_send_ns(local_dev, neigh, &dst_addr, &mc_dst_addr, &src_addr);
+#else
+		ndisc_send_ns(local_dev, &dst_addr, &mc_dst_addr, &src_addr);
+#endif
+		msleep(2000);
+
+		/*
+		 * Release hold on existing route entry, and find the route entry again
+		 */
 		ip6_rt_put(rt);
-		nss_connmgr_gre_warning("Err in MAC address, neighbour look up failed\n");
-		return GRE_ERR_NEIGH_LOOKUP;
+		rt = rt6_lookup(&init_net, &dst_addr, NULL, 0, 0);
+		if (!rt) {
+			nss_connmgr_gre_warning("Unable to find route lookup for %pI6\n", dest_ip);
+			return GRE_ERR_NEIGH_LOOKUP;
+		}
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
+		neigh = rt->dst.ops->neigh_lookup(&rt->dst, &dst_addr);
+#else
+		neigh = rt->dst.ops->neigh_lookup(&rt->dst, NULL, &dst_addr);
+#endif
+		if (!neigh || !is_valid_ether_addr(neigh->ha)) {
+			ip6_rt_put(rt);
+			nss_connmgr_gre_warning("Err in MAC address, neighbour look up failed\n");
+			return GRE_ERR_NEIGH_LOOKUP;
+		}
 	}
 
 	ether_addr_copy(dest_mac, neigh->ha);
@@ -222,8 +251,8 @@
 	/*
 	 * IP address validate
 	 */
-	if (!ipv6_addr_any(((const struct in6_addr *)&cfg->src_ip)) ||
-	    !ipv6_addr_any(((const struct in6_addr *)&cfg->dest_ip))) {
+	if (ipv6_addr_any(((const struct in6_addr *)&cfg->src_ip)) ||
+	    ipv6_addr_any(((const struct in6_addr *)&cfg->dest_ip))) {
 		nss_connmgr_gre_warning("Source ip/Destination IP is invalid");
 		return  GRE_ERR_INVALID_IP;
 	}
@@ -280,9 +309,21 @@
 	struct net_device *out_dev;
 	struct nss_gre_config_msg *cmsg = &req->msg.cmsg;
 	int ret;
+	struct in6_addr *src_ip = &t->parms.laddr;
+	struct in6_addr *dest_ip = &t->parms.raddr;
 
-	memcpy(cmsg->src_ip, t->parms.laddr.s6_addr, 16);
-	memcpy(cmsg->dest_ip, t->parms.raddr.s6_addr, 16);
+	/*
+	 * Store IPv6 addresses in host endian in the message.
+	 */
+	cmsg->src_ip[0] = ntohl(src_ip->in6_u.u6_addr32[0]);
+	cmsg->src_ip[1] = ntohl(src_ip->in6_u.u6_addr32[1]);
+	cmsg->src_ip[2] = ntohl(src_ip->in6_u.u6_addr32[2]);
+	cmsg->src_ip[3] = ntohl(src_ip->in6_u.u6_addr32[3]);
+
+	cmsg->dest_ip[0] = ntohl(dest_ip->in6_u.u6_addr32[0]);
+	cmsg->dest_ip[1] = ntohl(dest_ip->in6_u.u6_addr32[1]);
+	cmsg->dest_ip[2] = ntohl(dest_ip->in6_u.u6_addr32[2]);
+	cmsg->dest_ip[3] = ntohl(dest_ip->in6_u.u6_addr32[3]);
 
 	/*
 	 * IPv6 outer tos field is always inherited from inner IP header.