Browse Source

ipa: Move kernel-tests from ip_accelerator to techpack.

Move ip_accelerator which is a part of kernel-tests-internal
from kernel to techpack. Updated up to SHA1:
b8790774643dbfea5b312ed422ef86b54e4c8d7f

The kernel-test-module was moved into the driver,
and will be compiled as part of debug build.

Change-Id: I427b9ea061401c74845d2bd0d505da747d5fe89f
Acked-by: Eliad Ben Yishay <[email protected]>
Signed-off-by: Amir Levy <[email protected]>
Signed-off-by: Ilia Lin <[email protected]>
Ilia Lin 3 years ago
parent
commit
f1c1fb3a16
80 changed files with 47608 additions and 2 deletions
  1. 1 0
      config/dataipa_debug.conf
  2. 2 1
      config/dataipa_debug.h
  3. 3 0
      drivers/platform/msm/Kbuild
  4. 5 0
      drivers/platform/msm/ipa/Kbuild
  5. 404 0
      drivers/platform/msm/ipa/ipa_test_module/ipa_rm_ut.c
  6. 32 0
      drivers/platform/msm/ipa/ipa_test_module/ipa_rm_ut.h
  7. 101 0
      drivers/platform/msm/ipa/ipa_test_module/ipa_test_module.h
  8. 4666 0
      drivers/platform/msm/ipa/ipa_test_module/ipa_test_module_impl.c
  9. 8 0
      drivers/platform/msm/ipa/ipa_v3/ipa_i.h
  10. 2 1
      drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
  11. 395 0
      kernel-tests/Constants.h
  12. 105 0
      kernel-tests/DataPathTestFixture.cpp
  13. 82 0
      kernel-tests/DataPathTestFixture.h
  14. 391 0
      kernel-tests/DataPathTests.cpp
  15. 472 0
      kernel-tests/ExceptionTests.cpp
  16. 57 0
      kernel-tests/ExceptionsTestFixture.cpp
  17. 54 0
      kernel-tests/ExceptionsTestFixture.h
  18. 264 0
      kernel-tests/ExceptionsTests.cpp
  19. 127 0
      kernel-tests/Filtering.cpp
  20. 54 0
      kernel-tests/Filtering.h
  21. 513 0
      kernel-tests/FilteringEthernetBridgingTestFixture.cpp
  22. 104 0
      kernel-tests/FilteringEthernetBridgingTestFixture.h
  23. 700 0
      kernel-tests/FilteringEthernetBridgingTests.cpp
  24. 8585 0
      kernel-tests/FilteringTest.cpp
  25. 178 0
      kernel-tests/HeaderInsertion.cpp
  26. 59 0
      kernel-tests/HeaderInsertion.h
  27. 875 0
      kernel-tests/HeaderInsertionTests.cpp
  28. 618 0
      kernel-tests/HeaderProcessingContextTestFixture.cpp
  29. 218 0
      kernel-tests/HeaderProcessingContextTestFixture.h
  30. 780 0
      kernel-tests/HeaderProcessingContextTests.cpp
  31. 404 0
      kernel-tests/HeaderRemovalTestFixture.cpp
  32. 111 0
      kernel-tests/HeaderRemovalTestFixture.h
  33. 218 0
      kernel-tests/HeaderRemovalTests.cpp
  34. 73 0
      kernel-tests/HeaderRemovalTests.h
  35. 274 0
      kernel-tests/IPAFilteringTable.cpp
  36. 149 0
      kernel-tests/IPAFilteringTable.h
  37. 93 0
      kernel-tests/IPAInterruptsTestFixture.cpp
  38. 72 0
      kernel-tests/IPAInterruptsTestFixture.h
  39. 104 0
      kernel-tests/IPAInterruptsTests.cpp
  40. 409 0
      kernel-tests/IPv4Packet.cpp
  41. 179 0
      kernel-tests/IPv4Packet.h
  42. 1781 0
      kernel-tests/IPv6CTTest.cpp
  43. 155 0
      kernel-tests/InterfaceAbstraction.cpp
  44. 59 0
      kernel-tests/InterfaceAbstraction.h
  45. 59 0
      kernel-tests/Logger.cpp
  46. 60 0
      kernel-tests/Logger.h
  47. 1169 0
      kernel-tests/MBIMAggregationTestFixtureConf11.cpp
  48. 115 0
      kernel-tests/MBIMAggregationTestFixtureConf11.h
  49. 3366 0
      kernel-tests/MBIMAggregationTests.cpp
  50. 51 0
      kernel-tests/Makefile.am
  51. 26 0
      kernel-tests/NOTICE
  52. 4288 0
      kernel-tests/NatTest.cpp
  53. 729 0
      kernel-tests/Pipe.cpp
  54. 151 0
      kernel-tests/Pipe.h
  55. 107 0
      kernel-tests/PipeTestFixture.cpp
  56. 69 0
      kernel-tests/PipeTestFixture.h
  57. 478 0
      kernel-tests/PipeTests.cpp
  58. 11 0
      kernel-tests/README.txt
  59. 1097 0
      kernel-tests/RNDISAggregationTestFixture.cpp
  60. 113 0
      kernel-tests/RNDISAggregationTestFixture.h
  61. 1265 0
      kernel-tests/RNDISAggregationTests.cpp
  62. 183 0
      kernel-tests/RoutingDriverWrapper.cpp
  63. 63 0
      kernel-tests/RoutingDriverWrapper.h
  64. 5133 0
      kernel-tests/RoutingTests.cpp
  65. 94 0
      kernel-tests/TLPAggregationTestFixture.cpp
  66. 72 0
      kernel-tests/TLPAggregationTestFixture.h
  67. 946 0
      kernel-tests/TLPAggregationTests.cpp
  68. 74 0
      kernel-tests/TestBase.cpp
  69. 74 0
      kernel-tests/TestBase.h
  70. 396 0
      kernel-tests/TestManager.cpp
  71. 103 0
      kernel-tests/TestManager.h
  72. 1814 0
      kernel-tests/TestsUtils.cpp
  73. 798 0
      kernel-tests/TestsUtils.h
  74. 12 0
      kernel-tests/autogen.sh
  75. 129 0
      kernel-tests/build_kernel_tests.py
  76. 56 0
      kernel-tests/configure.ac
  77. 80 0
      kernel-tests/create_symlinks.sh
  78. 39 0
      kernel-tests/hton.h
  79. 388 0
      kernel-tests/main.cpp
  80. 64 0
      kernel-tests/run.sh

+ 1 - 0
config/dataipa_debug.conf

@@ -1,2 +1,3 @@
 export CONFIG_IPA_DEBUG=y
 export CONFIG_IPA_UT=y
+export CONFIG_IPA_KERNEL_TESTS_MODULE=y

+ 2 - 1
config/dataipa_debug.h

@@ -1,7 +1,8 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
-* Copyright (c) 2020, The Linux Foundation. All rights reserved.
+* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
 */
 
 #define CONFIG_IPA_DEBUG 1
 #define CONFIG_IPA_UT 1
+#define CONFIG_IPA_KERNEL_TESTS_MODULE 1

+ 3 - 0
drivers/platform/msm/Kbuild

@@ -52,6 +52,9 @@ LINUXINCLUDE += -I$(DATAIPADRVTOP)/ipa
 LINUXINCLUDE += -I$(DATAIPADRVTOP)/ipa/ipa_v3
 LINUXINCLUDE += -I$(DATAIPADRVTOP)/ipa/ipa_v3/ipahal
 LINUXINCLUDE += -I$(DATAIPADRVTOP)/ipa/ipa_clients
+ifneq (,$(filter $(CONFIG_IPA_KERNEL_TESTS_MODULE),y m))
+LINUXINCLUDE += -I$(DATAIPADRVTOP)/ipa/ipa_test_module
+endif
 endif
 
 ifneq (,$(filter $(CONFIG_IPA3_REGDUMP),y m))

+ 5 - 0
drivers/platform/msm/ipa/Kbuild

@@ -49,10 +49,15 @@ ipam-$(CONFIG_IPA_UT) += test/ipa_ut_framework.o test/ipa_test_example.o \
 	test/ipa_test_hw_stats.o test/ipa_pm_ut.o \
 	test/ipa_test_wdi3.o
 
+ipatestm-$(CONFIG_IPA_KERNEL_TESTS_MODULE) += \
+	ipa_test_module/ipa_test_module_impl.o \
+	ipa_test_module/ipa_rm_ut.o
+
 ipanetm-y += ipa_v3/ipa_net.o
 
 obj-$(CONFIG_IPA3) += ipam.o
 obj-$(CONFIG_IPA3) += ipanetm.o
+obj-$(CONFIG_IPA_KERNEL_TESTS_MODULE) += ipatestm.o
 
 obj-y += ipa_v3/ ipa_clients/
 

+ 404 - 0
drivers/platform/msm/ipa/ipa_test_module/ipa_rm_ut.c

@@ -0,0 +1,404 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*/
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/ipa.h>
+#include <linux/msm_ipa.h>
+#include <linux/kernel.h>
+#include "ipa_rm_ut.h"
+
+#define IPA_UT_DBG(x...) pr_err(x)
+
+/**
+ * enum ut_wq_cmd - workqueue commands
+ */
+enum ut_wq_cmd {
+	UT_WQ_REQ,
+	UT_WQ_REL
+};
+
+/**
+ * struct ipa_rm_ut_wq_work_type - IPA RM worqueue specific
+ *				work type
+ * @work: work struct
+ * @wq_cmd: command that should be processed in workqueue context
+ * @resource_name: name of the resource on which this work
+ *			should be done
+ * @dep_graph: data structure to search for resource if exists
+ * @event: event to notify
+ */
+struct ipa_rm_ut_wq_work_type {
+	struct work_struct		work;
+	enum ut_wq_cmd			wq_cmd;
+	enum ipa_rm_resource_name	resource_name;
+	enum ipa_rm_event		event;
+};
+
+
+
+static struct {
+	int (*add_dependency)(enum ipa_rm_resource_name
+					dependant_name,
+					enum ipa_rm_resource_name
+					dependency_name);
+	int (*resource_request)(enum ipa_rm_resource_name resource_name);
+	int (*resource_release)(enum ipa_rm_resource_name resource_name);
+	int (*consumer_cb)(enum ipa_rm_event,
+			enum ipa_rm_resource_name resource_name);
+	struct workqueue_struct *wq;
+} ipa_rm_ut_cb;
+
+struct device_manager_type {
+	void *user_data;
+	ipa_rm_notify_cb notify_cb;
+	int (*release_function)(void);
+	int (*request_function)(void);
+};
+
+static void ipa_ut_wq_handler(struct work_struct *work);
+int ipa_ut_wq_send_cmd(enum ut_wq_cmd wq_cmd,
+		enum ipa_rm_resource_name resource_name,
+		enum ipa_rm_event event);
+static int usb_mgr_release_function(void);
+static int usb_mgr_request_function(void);
+static void usb_mgr_notify_function(void *user_data,
+		enum ipa_rm_event event,
+		unsigned long data);
+
+static struct device_manager_type usb_device_manager = {
+	NULL,
+	usb_mgr_notify_function,
+	usb_mgr_release_function,
+	usb_mgr_request_function
+};
+
+/* USB device manager */
+static int usb_mgr_release_function(void)
+{
+	IPA_UT_DBG("USB Released\n");
+	IPA_UT_DBG("ASYNC CALL USB calling to IPA RM provided CB\n");
+	ipa_ut_wq_send_cmd(UT_WQ_REL,
+			IPA_RM_RESOURCE_USB_CONS,
+			IPA_RM_RESOURCE_RELEASED);
+
+	return -EINPROGRESS;
+}
+
+static int usb_mgr_request_function(void)
+{
+	IPA_UT_DBG("USB Requested\n");
+	IPA_UT_DBG("ASYNC CALL USB calling to IPA RM provided CB\n");
+	ipa_ut_wq_send_cmd(UT_WQ_REQ,
+			IPA_RM_RESOURCE_USB_CONS,
+			IPA_RM_RESOURCE_GRANTED);
+
+	return -EINPROGRESS;
+}
+
+static void usb_mgr_notify_function(void *notify_cb_data,
+		enum ipa_rm_event event,
+		unsigned long data)
+{
+	IPA_UT_DBG("USB got event [%d]\n", event);
+}
+
+/* HSIC device manager */
+static int hsic_mgr_release_function(void)
+{
+	int result = 0;
+	IPA_UT_DBG("HSIC Released\n");
+	IPA_UT_DBG("HSIC calling to IPA RM provided CB\n");
+	result = ipa_rm_ut_cb.consumer_cb(IPA_RM_RESOURCE_RELEASED,
+			IPA_RM_RESOURCE_HSIC_CONS);
+
+	return -EINPROGRESS;
+}
+
+static int hsic_mgr_request_function(void)
+{
+	int result = 0;
+	IPA_UT_DBG("HSIC Requested\n");
+	IPA_UT_DBG("HSIC calling to IPA RM provided CB\n");
+	result = ipa_rm_ut_cb.consumer_cb(IPA_RM_RESOURCE_GRANTED,
+			IPA_RM_RESOURCE_HSIC_CONS);
+
+	return -EINPROGRESS;
+}
+
+static void hsic_notify_function(void *notify_cb_data,
+		enum ipa_rm_event event,
+		unsigned long data)
+{
+	IPA_UT_DBG("HSIC got event [%d]\n", event);
+}
+
+static struct device_manager_type hsic_device_manager = {
+	NULL,
+	hsic_notify_function,
+	hsic_mgr_release_function,
+	hsic_mgr_request_function
+};
+
+static void rmnet_bridge_mgr_notify_function
+		(void *notify_cb_data,
+		enum ipa_rm_event event,
+		unsigned long data)
+{
+	IPA_UT_DBG("RmNet got event [%d]\n", event);
+}
+
+static struct device_manager_type rmnet_bridge_device_manager = {
+	NULL,
+	rmnet_bridge_mgr_notify_function,
+	NULL,
+	NULL
+};
+
+
+static void ipa_ut_wq_handler(struct work_struct *work)
+{
+	enum ut_wq_cmd ut_cmd;
+	struct ipa_rm_ut_wq_work_type *ipa_rm_work =
+		(struct ipa_rm_ut_wq_work_type *)work;
+	if (!ipa_rm_work)
+		return;
+	ut_cmd = (enum ut_wq_cmd)ipa_rm_work->wq_cmd;
+	IPA_UT_DBG("***UT CMD Q command [%d]\n", ut_cmd);
+	switch (ut_cmd) {
+	case UT_WQ_REQ:
+		switch (ipa_rm_work->resource_name) {
+		case IPA_RM_RESOURCE_USB_CONS:
+			IPA_UT_DBG
+			("***calling to USB consumer notify request CB\n");
+			ipa_rm_ut_cb.consumer_cb(IPA_RM_RESOURCE_GRANTED,
+					IPA_RM_RESOURCE_USB_CONS);
+			break;
+		case IPA_RM_RESOURCE_HSIC_CONS:
+			break;
+		default:
+			return;
+		}
+		break;
+	case UT_WQ_REL:
+		switch (ipa_rm_work->resource_name) {
+		case IPA_RM_RESOURCE_USB_CONS:
+			IPA_UT_DBG
+			("***calling to USB consumer notify release CB\n");
+			ipa_rm_ut_cb.consumer_cb(IPA_RM_RESOURCE_RELEASED,
+					IPA_RM_RESOURCE_USB_CONS);
+			break;
+		case IPA_RM_RESOURCE_HSIC_CONS:
+			break;
+		default:
+			return;
+		}
+		break;
+	default:
+		break;
+	}
+
+	kfree((void *) work);
+}
+
+int ipa_ut_wq_send_cmd(enum ut_wq_cmd wq_cmd,
+		enum ipa_rm_resource_name resource_name,
+		enum ipa_rm_event event)
+{
+	int result = 0;
+	struct ipa_rm_ut_wq_work_type *work =
+	(struct ipa_rm_ut_wq_work_type *)
+		kzalloc(sizeof(*work), GFP_KERNEL);
+	if (work) {
+		INIT_WORK((struct work_struct *)work, ipa_ut_wq_handler);
+		work->wq_cmd = (enum ut_wq_cmd) wq_cmd;
+		work->resource_name = resource_name;
+		work->event = event;
+		result = queue_work(ipa_rm_ut_cb.wq,
+				(struct work_struct *)work);
+	} else {
+		result = -ENOMEM;
+	}
+	return result;
+}
+
+/**
+ * build_rmnet_bridge_use_case_graph() - simulate resource creation
+ *
+ * @create_resource: create resource function provided by ipa_rm
+ * unit under test
+ * @consumer_cb: consumer CB function provided by ipa_rm
+ * unit under test
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int build_rmnet_bridge_use_case_graph(
+		int (*create_resource)
+			(struct ipa_rm_create_params *create_params),
+		int (*consumer_cb)(enum ipa_rm_event event,
+				enum ipa_rm_resource_name resource_name))
+{
+	int result = 0;
+	struct ipa_rm_create_params create_params = {0};
+
+	IPA_UT_DBG("build_rmnet_bridge_use_case_graph ENTER\n");
+
+	ipa_rm_ut_cb.consumer_cb = consumer_cb;
+
+	/* create USB PROD */
+	create_params.name = IPA_RM_RESOURCE_USB_PROD;
+	create_params.reg_params.notify_cb =
+			usb_device_manager.notify_cb;
+	create_params.reg_params.user_data =
+			usb_device_manager.user_data;
+	result = create_resource(&create_params);
+	if (result)
+		goto bail;
+
+	/* create USB CONS */
+	create_params.name = IPA_RM_RESOURCE_USB_CONS;
+	create_params.release_resource =
+			usb_device_manager.release_function;
+	create_params.request_resource =
+			usb_device_manager.request_function;
+	result = create_resource(&create_params);
+	if (result)
+		goto bail;
+
+	/* create HSIC PROD */
+	create_params.name = IPA_RM_RESOURCE_HSIC_PROD;
+	create_params.reg_params.notify_cb =
+			hsic_device_manager.notify_cb;
+	create_params.reg_params.user_data =
+			hsic_device_manager.user_data;
+	result = create_resource(&create_params);
+	if (result)
+		goto bail;
+
+	/* create HSIC CONS */
+	create_params.name = IPA_RM_RESOURCE_HSIC_CONS;
+	create_params.release_resource =
+			hsic_device_manager.release_function;
+	create_params.request_resource =
+			hsic_device_manager.request_function;
+	result = create_resource(&create_params);
+	if (result)
+		goto bail;
+
+	/* BRIDGE PROD */
+	create_params.name = IPA_RM_RESOURCE_WWAN_0_PROD;
+	create_params.reg_params.notify_cb =
+			rmnet_bridge_device_manager.notify_cb;
+	create_params.reg_params.user_data =
+			rmnet_bridge_device_manager.user_data;
+	result = create_resource(&create_params);
+	if (result)
+		goto bail;
+
+	ipa_rm_ut_cb.wq = create_singlethread_workqueue("ut_wq");
+	if (!ipa_rm_ut_cb.wq) {
+		result = -ENOMEM;
+		goto bail;
+	}
+
+	IPA_UT_DBG("build_rmnet_bridge_use_case_graph EXIT SUCCESS\n");
+
+bail:
+
+	return result;
+}
+
+/**
+ * build_rmnet_bridge_use_case_dependencies() - simulate build
+ *			dependency graph process
+ * @add_dependency: add dependency function provided by ipa_rm
+ * unit under test
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int build_rmnet_bridge_use_case_dependencies(
+		int (*add_dependency)
+			(enum ipa_rm_resource_name dependant_name,
+		enum ipa_rm_resource_name dependency_name))
+{
+	int result = 0;
+
+	IPA_UT_DBG("build_rmnet_bridge_use_case_dependencies ENTER\n");
+
+	ipa_rm_ut_cb.add_dependency = add_dependency;
+
+	result = add_dependency(IPA_RM_RESOURCE_USB_PROD,
+			IPA_RM_RESOURCE_HSIC_CONS);
+	if (result)
+		goto bail;
+	result = add_dependency(IPA_RM_RESOURCE_HSIC_PROD,
+			IPA_RM_RESOURCE_USB_CONS);
+	if (result)
+		goto bail;
+	result = add_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
+			IPA_RM_RESOURCE_HSIC_CONS);
+	if (result)
+		goto bail;
+	result = add_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
+			IPA_RM_RESOURCE_USB_CONS);
+
+	if (result)
+		goto bail;
+
+bail:
+	IPA_UT_DBG(
+		"build_rmnet_bridge_use_case_dependencies EXIT result [%d]\n",
+		result);
+	return result;
+}
+
+/**
+ * request_release_resource_sequence() - simulate request / release
+ *			resource sequence
+ * @resource_request: request resource function provided by ipa_rm
+ * unit under test
+ * @resource_release: release resource function provided by ipa_rm
+ * unit under test
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int request_release_resource_sequence(
+		int (*resource_request)
+			(enum ipa_rm_resource_name resource_name),
+		int (*resource_release)
+			(enum ipa_rm_resource_name resource_name))
+{
+	int result = 0;
+	ipa_rm_ut_cb.resource_request = resource_request;
+	ipa_rm_ut_cb.resource_release = resource_release;
+
+	IPA_UT_DBG("request_release_resource_sequence ENTER\n");
+
+	result = resource_request(IPA_RM_RESOURCE_USB_PROD);
+	IPA_UT_DBG("result [%d]\n", result);
+	result = resource_request(IPA_RM_RESOURCE_HSIC_PROD);
+	IPA_UT_DBG("result [%d]\n", result);
+
+	result = resource_release(IPA_RM_RESOURCE_USB_PROD);
+	IPA_UT_DBG("result [%d]\n", result);
+	result = resource_release(IPA_RM_RESOURCE_HSIC_PROD);
+	IPA_UT_DBG("result [%d]\n", result);
+
+	IPA_UT_DBG("request_release_resource_sequence EXIT SUCCESS\n");
+	return result;
+}
+
+/**
+ * clean_ut() - free unit test module resources
+ *
+ */
+void clean_ut(void)
+{
+	IPA_UT_DBG("clean_ut ENTER\n");
+	if (ipa_rm_ut_cb.wq)
+		destroy_workqueue(ipa_rm_ut_cb.wq);
+	IPA_UT_DBG("clean_ut EXIT SUCCESS\n");
+}

+ 32 - 0
drivers/platform/msm/ipa/ipa_test_module/ipa_rm_ut.h

@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*/
+
+#ifndef _IPA_RM_UT_H_
+#define _IPA_RM_UT_H_
+
+/**
+ * ipa_rm_ut - unit test module
+ * Defines sanity test scenarios executed from debugfs
+ * writer function defined in ipa_rm module
+ */
+
+#include <linux/msm_ipa.h>
+#include <linux/ipa.h>
+
+int build_rmnet_bridge_use_case_graph(
+		int (*create_resource)(struct ipa_rm_create_params *create_params),
+		int (*consumer_cb)(enum ipa_rm_event event,
+				enum ipa_rm_resource_name resource_name));
+
+int build_rmnet_bridge_use_case_dependencies(
+		int (*add_dependency)(enum ipa_rm_resource_name dependant_name,
+						enum ipa_rm_resource_name dependency_name));
+int request_release_resource_sequence(
+		int (*resource_request)(enum ipa_rm_resource_name resource_name),
+		int (*resource_release)(enum ipa_rm_resource_name resource_name));
+
+void clean_ut(void);
+
+#endif /* _IPA_RM_UT_H_ */

+ 101 - 0
drivers/platform/msm/ipa/ipa_test_module/ipa_test_module.h

@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+* Copyright (c) 2017-2018,2020, The Linux Foundation. All rights reserved.
+*/
+
+#ifndef _IPA_TEST_MODULE_H_
+#define _IPA_TEST_MODULE_H_
+
+#include <stddef.h>
+#include <linux/msm_ipa.h>
+#include <linux/ioctl.h>
+#ifdef _KERNEL_
+#include <linux/ipa.h>
+#endif
+
+#define IPA_TEST_IOC_MAGIC 0xA5
+enum {
+	IPA_TEST_IOCTL_GET_HW_TYPE = 1,
+	IPA_TEST_IOCTL_CONFIGURE,
+	IPA_TEST_IOCTL_CLEAN,
+	IPA_TEST_IOCTL_EP_CTRL,
+	IPA_TEST_IOCTL_REG_SUSPEND_HNDL,
+	IPA_TEST_IOCTL_HOLB_CONFIG,
+	IPA_TEST_IOCTL_NUM,
+};
+
+#define IPA_TEST_IOC_GET_HW_TYPE _IO(IPA_TEST_IOC_MAGIC, \
+		IPA_TEST_IOCTL_GET_HW_TYPE)
+#define IPA_TEST_IOC_CONFIGURE _IOWR(IPA_TEST_IOC_MAGIC, \
+		IPA_TEST_IOCTL_CONFIGURE, \
+		struct ipa_test_config_header *)
+#define IPA_TEST_IOC_CLEAN _IO(IPA_TEST_IOC_MAGIC, \
+		IPA_TEST_IOCTL_CLEAN)
+#define IPA_TEST_IOC_EP_CTRL _IOWR(IPA_TEST_IOC_MAGIC, \
+		IPA_TEST_IOCTL_EP_CTRL, \
+		struct ipa_test_ep_ctrl *)
+#define IPA_TEST_IOC_REG_SUSPEND_HNDL _IOWR(IPA_TEST_IOC_MAGIC, \
+		IPA_TEST_IOCTL_REG_SUSPEND_HNDL, \
+		struct ipa_test_reg_suspend_handler *)
+#define IPA_TEST_IOC_HOLB_CONFIG _IOWR(IPA_TEST_IOC_MAGIC, \
+		IPA_TEST_IOCTL_HOLB_CONFIG, \
+		struct handle_holb_config_ioctl *)
+
+#define IPA_TEST_CONFIG_MARKER 0x57
+#define IPA_TEST_CHANNEL_CONFIG_MARKER 0x83
+
+/*
+ * This is the configuration number that is saved for Generic configuration
+ * we need it in order to allow coexistence of Generic
+ * configured tests with old fashion tests
+ */
+#define GENERIC_TEST_CONFIGURATION_IDX 37788239
+
+struct ipa_test_config_header
+{
+	unsigned char head_marker; /* IPA_TEST_CONFIG_MARKER */
+	int to_ipa_channels_num;
+	struct ipa_channel_config **to_ipa_channel_config;
+	int from_ipa_channels_num;
+	struct ipa_channel_config **from_ipa_channel_config;
+	unsigned char tail_marker; /* IPA_TEST_CONFIG_MARKER */
+};
+
+struct ipa_test_en_status
+{
+	int num_clients;
+	enum ipa_client_type *clients;
+};
+
+struct ipa_test_ep_ctrl
+{
+	bool ipa_ep_suspend;
+	bool ipa_ep_delay;
+	int from_dev_num;
+};
+
+struct ipa_test_reg_suspend_handler
+{
+	int DevNum;
+	bool reg;
+	bool deferred_flag;
+};
+
+struct ipa_channel_config
+{
+	unsigned char head_marker; /* IPA_TEST_CHANNEL_CONFIG_MARKER */
+	enum ipa_client_type client;
+	int index; /* shall be used for to_ipa_x or from_ipa_x */
+	size_t config_size;
+	void *cfg;
+	bool en_status;
+	unsigned char tail_marker; /* IPA_TEST_CHANNEL_CONFIG_MARKER */
+};
+
+struct ipa_test_holb_config
+{
+	enum ipa_client_type client;
+	unsigned tmr_val;
+	unsigned short en;
+};
+#endif /* _IPA_TEST_MODULE_H_ */

+ 4666 - 0
drivers/platform/msm/ipa/ipa_test_module/ipa_test_module_impl.c

@@ -0,0 +1,4666 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+*/
+
+#include <linux/types.h>	/* u32 */
+#include <linux/kernel.h>	/* pr_debug() */
+#include <linux/slab.h>		/* kzalloc() */
+#include <linux/mutex.h>	/* mutex */
+#include <linux/list.h>		/* list_head */
+#include <linux/delay.h>	/* msleep */
+#include <linux/memory.h>	/* memset */
+#include <linux/device.h>	/* device */
+#include <linux/cdev.h>		/* cdev_alloc() */
+#include <linux/fs.h>		/* alloc_chrdev_region() */
+#include <linux/module.h>	/* module_init() */
+#include <linux/dma-mapping.h>	/* dma_alloc_coherent() */
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/ipa.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>	/* sk_buff */
+#include <linux/kfifo.h>  /* Kernel FIFO Implementation */
+#include <linux/delay.h> /* msleep() */
+#include <linux/string.h>
+#include <linux/printk.h>
+#include <linux/msm_gsi.h>
+#include "gsi.h"
+#include "ipa_i.h"
+#include "ipa_rm_ut.h"
+#include "ipa_test_module.h"
+
+#ifdef INIT_COMPLETION
+#define reinit_completion(x) INIT_COMPLETION(*(x))
+#endif /* INIT_COMPLETION */
+
+
+/** Module name string */
+#define IPA_TEST_DRV_NAME "ipa_test"
+
+//#define IPA_SUMMING_THRESHOLD 0x10
+#define IPA_EVENT_THRESHOLD 0x10
+#define IPA_NUM_PIPES 0x24
+
+#define TEST_SIGNATURE 0xfacecafe
+#define DFAB_ARB1_HCLK_CTL		(MSM_CLK_CTL_BASE + 0x2564)
+
+#define DESC_FIFO_SZ 0x100
+#define DATA_FIFO_SZ 0x2000
+
+#define GSI_CHANNEL_RING_LEN 4096
+#define GSI_EVT_RING_LEN 4096
+
+#define TX_NUM_BUFFS 16
+#define TX_SZ 32768
+#define TX_BUFF_SIZE ((TX_SZ)/(TX_NUM_BUFFS))
+
+#define RX_NUM_BUFFS 16
+#define RX_SZ 32768
+#define RX_BUFF_SIZE ((RX_SZ)/(RX_NUM_BUFFS))
+
+#define IPA_TEST_DMUX_HEADER_LENGTH           8
+#define IPA_TEST_META_DATA_IS_VALID           1
+#define IPA_TEST_DMUX_HEADER_META_DATA_OFFSET 4
+
+#define IPA_TEST_ADDITIONAL_HDR_LEN 4
+
+#define IPA_TEST_META_DATA_OFFSET_NONE        0
+
+#define IPA_TEST_HDI_802_HEADER_LENGTH             22
+#define IPA_TEST_HDI_802_LENGTH_FIELD_OFFSET       11
+#define IPA_TEST_HDI_802_LENGTH_FIELD_OFFSET_VALID  1
+#define IPA_TEST_HDI_802_ADD_CONST_LENGTH           0
+
+#define IPA_TEST_HDI_RMNET_HEADER_LENGTH              6
+#define IPA_TEST_HDI_RMNET_LENGTH_FIELD_OFFSET        0
+#define IPA_TEST_HDI_RMNET_LENGTH_FIELD_OFFSET_VALID  0
+#define IPA_TEST_HDI_RMNET_ADD_CONST_LENGTH           0
+
+/* Settings of Exception Handling */
+#define RX_DESCRIPTOR_SIZE 2048
+#define EXCEPTION_DRV_NAME "ipa_exception_pipe"
+#define EXCEPTION_KFIFO_SIZE (8)
+#define EXCEPTION_KFIFO_SLEEP_MS (EXCEPTION_KFIFO_SLEEP_MS)
+#define EXCEPTION_KFIFO_DEBUG_VERBOSE 1
+#define SAVE_HEADER 1
+
+#define IPATEST_DBG(fmt, args...) \
+	do { \
+		pr_debug(IPA_TEST_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args);\
+	} while (0)
+
+#define IPATEST_ERR(fmt, args...) \
+	do { \
+		pr_err(IPA_TEST_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args);\
+	} while (0)
+
+#define IPATEST_DUMP(fmt, args...) \
+	do { \
+		pr_debug(fmt, ## args);\
+	} while (0)
+
+int ipa_sys_setup(struct ipa_sys_connect_params *sys_in,
+		  unsigned long *ipa_gsi_hdl,
+		  u32 *ipa_pipe_num, u32 *clnt_hdl, bool en_status);
+int ipa_sys_teardown(u32 clnt_hdl);
+int ipa_sys_update_gsi_hdls(u32 clnt_hdl, unsigned long gsi_ch_hdl,
+	unsigned long gsi_ev_hdl);
+struct device *ipa_get_pdev(void);
+enum fops_type {
+	IPA_TEST_REG_CHANNEL,
+	IPA_TEST_DATA_PATH_TEST_CHANNEL,
+	MAX_FOPS
+};
+
+struct notify_cb_data_st {
+	struct kfifo_rec_ptr_2 exception_kfifo;
+};
+
+struct exception_hdl_data {
+	struct class *class;
+	struct device *dev;
+	struct cdev *p_cdev;
+	dev_t dev_num;
+	struct notify_cb_data_st notify_cb_data;
+};
+
+/*struct exception_hdl_data *p_exception_hdl_data = NULL;*/
+struct exception_hdl_data *p_exception_hdl_data;
+
+struct ipa_dma_chan {
+	u32 dest_pipe_index;
+	u32 src_pipe_index;
+};
+
+/**
+ *  This struct specifies memory buffer properties.
+ *
+ * @base - Buffer virtual address.
+ * @phys_base - Buffer physical address.
+ * @size - Specifies buffer size (or maximum size).
+ *
+ */
+//struct ipa_mem_buffer {
+//	void *base;
+//	phys_addr_t phys_base;
+//	u32 size;
+//};
+
+struct test_endpoint_sys {
+	struct completion xfer_done; /*A completion object for end transfer*/
+	struct gsi_chan_props gsi_channel_props;
+	struct gsi_evt_ring_props gsi_evt_ring_props;
+	bool gsi_valid;
+	unsigned long gsi_chan_hdl;
+	unsigned long gsi_evt_ring_hdl;
+};
+
+#define MAX_CHANNEL_NAME (20)
+
+/* A channel device is the representation of the flow of data from APPS
+	to IPA and vice versa. */
+struct channel_dev {
+	/*OS structures for representation of a channel.*/
+	struct class *class;
+	dev_t dev_num;
+	struct device *dev;
+	struct cdev cdev;
+
+	/*The representation of the connection from APPS to GSI/IPA*/
+	struct test_endpoint_sys ep;
+	/*The representation of the connection from GSI to IPA*/
+	struct ipa_dma_chan dma_ep;
+	/*The data FIFO for the APPS to IPA*/
+	struct ipa_mem_buffer mem;
+	/*Index of the next available buffer to use under mem.buff*/
+	int mem_buff_index;
+	/*A pointer to the test context - should be deleted - TODO*/
+	struct test_context *test;
+
+	int index;/*to_ipa_<index>/from_ipa_<index>*/
+	char name[MAX_CHANNEL_NAME];
+	int rx_pool_inited;/*check... - should be moved to contex?*/
+	int ipa_client_hdl;/*returned from ipa_connect*/
+};
+
+#define MAX_CHANNEL_DEVS (10)
+static struct channel_dev *to_ipa_devs[MAX_CHANNEL_DEVS/2];
+/*TODO - legacy*/
+static struct channel_dev *from_ipa_devs[MAX_CHANNEL_DEVS/2];
+
+/*This structure holds all the data required for the test module.*/
+struct test_context {
+
+	/*OS structures for representation of the test module.*/
+	dev_t dev_num;
+	struct device *dev;
+	struct cdev *cdev;
+
+	/*All channels that are used to read data from
+	 * the IPA(Receive channel)*/
+	struct channel_dev *rx_channels[MAX_CHANNEL_DEVS/2];
+
+	/*All channels that are used to write data
+	 * to the IPA(Transmit channel)*/
+	struct channel_dev *tx_channels[MAX_CHANNEL_DEVS/2];
+	int num_rx_channels;
+	int num_tx_channels;
+
+	/*current test case(-EINVAL is for not-configured)TODO*/
+	s32 configuration_idx;
+	s32 current_configuration_idx;
+
+	u32 signature;/*Legacy*/
+};
+
+/**
+ * struct ipa_tx_suspend_private_data - private data for IPA_TX_SUSPEND_IRQ use
+ * @clnt_hdl: client handle assigned by IPA
+ */
+struct ipa_tx_suspend_private_data {
+	u32 clnt_hdl;
+	u32 gsi_chan_hdl;
+};
+
+static struct test_context *ipa_test;
+
+
+/**
+ * Allocate memory from system memory.
+ *
+ * @param mem
+ */
+static void test_alloc_mem(struct ipa_mem_buffer *mem)
+{
+	dma_addr_t dma_addr;
+
+	/* need to check return value in formal code */
+	mem->base = dma_alloc_coherent(ipa3_get_pdev(), mem->size, &dma_addr, GFP_KERNEL);
+	mem->phys_base = dma_addr;
+}
+
+/**
+ * Free memory from system memory.
+ *
+ * @param mem
+ */
+static void test_free_mem(struct ipa_mem_buffer *mem)
+{
+	dma_addr_t dma_addr = mem->phys_base;
+
+	if (dma_addr)
+		dma_free_coherent(ipa3_get_pdev(), mem->size, mem->base, dma_addr);
+
+	mem->phys_base = 0;
+	mem->base = NULL;
+}
+
+void print_buff(void *data, size_t size)
+{
+	u8 bytes_in_line = 16;
+	int i, j, num_lines;
+	char str[256], tmp[4];
+
+	num_lines = size / bytes_in_line;
+	if (size % bytes_in_line > 0)
+		num_lines++;
+
+	IPATEST_DBG("Printing buffer at address 0x%px, size = %zu:\n"
+		, data, size);
+	for (i = 0; i < num_lines; i++) {
+		str[0] = '\0';
+		for (j = 0; (j < bytes_in_line) &&
+			((i * bytes_in_line + j) < size); j++) {
+			snprintf(tmp, sizeof(tmp), "%02x ",
+					((unsigned char *)data)
+					[i * bytes_in_line + j]);
+			strlcat(str, tmp, sizeof(str));
+		}
+		IPATEST_DUMP(": %s\n", str);
+	}
+}
+
+static int channel_open(struct inode *inode, struct file *filp)
+{
+	struct channel_dev *channel_dev;
+
+	/* Get the channel device data */
+	channel_dev = container_of(inode->i_cdev, struct channel_dev, cdev);
+
+	IPATEST_DBG("channel_dev address = 0x%px\n", channel_dev);
+
+	filp->private_data = channel_dev;
+
+	return 0;
+}
+
+int insert_descriptors_into_rx_endpoints(u32 count)
+{
+	struct channel_dev *rx_channel = NULL;
+	int i, j, res = 0;
+
+	/* Insert a descriptor into the receiving end(s) */
+	for (i = 0; i < ipa_test->num_rx_channels; i++) {
+		rx_channel = ipa_test->rx_channels[i];
+		if (!rx_channel->rx_pool_inited) {
+			res = 0;
+			for (j = 0; j < RX_NUM_BUFFS; j++) {
+				struct gsi_xfer_elem gsi_xfer;
+
+				memset(&gsi_xfer, 0, sizeof(gsi_xfer));
+				gsi_xfer.addr = rx_channel->mem.phys_base + j * count;
+				gsi_xfer.flags |= GSI_XFER_FLAG_EOT;
+				gsi_xfer.len = count;
+				gsi_xfer.type = GSI_XFER_ELEM_DATA;
+				gsi_xfer.xfer_user_data = (void*)(rx_channel->mem.phys_base + j * count);
+
+				IPATEST_DBG("submitting credit to gsi\n");
+				res |= gsi_queue_xfer(rx_channel->ep.gsi_chan_hdl, 1, &gsi_xfer, true);
+				if (res) {
+					IPATEST_ERR("gsi_queue_xfer failed %d\n", res);
+					return -EFAULT;
+				}
+			}
+
+			if (res == 0)
+				rx_channel->rx_pool_inited = 1;
+		}
+	}
+
+	return res;
+}
+
+static ssize_t channel_write_gsi(struct file *filp, const char __user *buf,
+	size_t count, loff_t *f_pos)
+{
+	struct channel_dev *channel_dev = filp->private_data;
+	int res = 0;
+	void *data_address = channel_dev->mem.base
+		+ channel_dev->mem_buff_index * TX_BUFF_SIZE;
+	u32 data_phys_addr = channel_dev->mem.phys_base
+		+ channel_dev->mem_buff_index * TX_BUFF_SIZE;
+	struct gsi_xfer_elem gsi_xfer;
+
+	if (count > (RX_BUFF_SIZE))
+		IPATEST_ERR("-----PROBLEM----- count=%zu RX_BUFF_SIZE=%d\n",
+		count, RX_BUFF_SIZE);
+
+	/* Copy the data from the user and transmit */
+	res = copy_from_user(data_address, buf, count);
+	if (res) {
+		IPATEST_ERR("copy_from_user() failure.\n");
+		return -EINVAL;
+	}
+
+	/* Print the data */
+	print_buff(data_address, count);
+
+	IPATEST_DBG("-----Start Transfer-----\n");
+
+	/* Transmit */
+	memset(&gsi_xfer, 0, sizeof(gsi_xfer));
+	gsi_xfer.addr = data_phys_addr;
+	gsi_xfer.flags |= GSI_XFER_FLAG_EOT;
+	gsi_xfer.len = count;
+	gsi_xfer.type = GSI_XFER_ELEM_DATA;
+
+	IPATEST_DBG("sending a packet to gsi\n");
+	res = gsi_queue_xfer(channel_dev->ep.gsi_chan_hdl, 1, &gsi_xfer, true);
+	if (res != GSI_STATUS_SUCCESS) {
+		IPATEST_ERR("GSI xfer failed %d\n", res);
+		return res;
+	}
+
+	channel_dev->mem_buff_index = (channel_dev->mem_buff_index + 1) %
+					TX_NUM_BUFFS;
+	return count;
+}
+
+static ssize_t channel_read_gsi(struct file *filp, char __user *buf,
+	size_t count, loff_t *f_pos)
+{
+	struct channel_dev *channel_dev = filp->private_data;
+	int res = 0;
+	int i;
+	phys_addr_t offset = 0;
+	struct gsi_chan_xfer_notify xfer_notify;
+	int max_retry = 10;
+	struct gsi_xfer_elem gsi_xfer;
+
+	IPATEST_DBG("size to read = %zu\n", count);
+	for (i = 0; i < max_retry; i++) {
+		res = gsi_poll_channel(channel_dev->ep.gsi_chan_hdl,
+			&xfer_notify);
+
+		if (res != GSI_STATUS_SUCCESS && res != GSI_STATUS_POLL_EMPTY) {
+			IPATEST_ERR("gsi_poll_channel failed %d\n", res);
+			return res;
+		}
+		if (res == GSI_STATUS_SUCCESS)
+			break;
+
+		IPATEST_DBG("channel empty %d/%d\n", i + 1, max_retry);
+		msleep(5);
+	}
+
+	if (i == max_retry) {
+		IPATEST_ERR("transfer not completed.\n");
+		return 0;
+	}
+
+	IPATEST_DBG("received %d bytes from 0x%px.\n",
+		xfer_notify.bytes_xfered, xfer_notify.xfer_user_data);
+
+	/* Copy the received data to the user buffer */
+	offset = (phys_addr_t)xfer_notify.xfer_user_data - channel_dev->mem.phys_base;
+	res = copy_to_user(buf,
+		channel_dev->mem.base + offset,
+		xfer_notify.bytes_xfered);
+	if (res < 0) {
+		IPATEST_ERR("copy_to_user() failed.\n");
+		return 0;
+	}
+
+	/* Re-insert the descriptor back to pipe */
+	memset(&gsi_xfer, 0, sizeof(gsi_xfer));
+	gsi_xfer.addr = (phys_addr_t)xfer_notify.xfer_user_data;
+	gsi_xfer.flags |= GSI_XFER_FLAG_EOT;
+	gsi_xfer.len = RX_BUFF_SIZE;
+	gsi_xfer.type = GSI_XFER_ELEM_DATA;
+	gsi_xfer.xfer_user_data = xfer_notify.xfer_user_data;
+
+	IPATEST_DBG("submitting credit to gsi\n");
+	res = gsi_queue_xfer(channel_dev->ep.gsi_chan_hdl, 1, &gsi_xfer, true);
+	if (res) {
+		IPATEST_ERR("gsi_queue_xfer failed %d\n", res);
+		return 0;
+	}
+
+	IPATEST_DBG("Returning %d.\n", xfer_notify.bytes_xfered);
+	return xfer_notify.bytes_xfered;
+}
+
+static ssize_t channel_write(struct file *filp, const char __user *buf,
+	size_t count, loff_t *f_pos)
+{
+	return channel_write_gsi(filp, buf, count, f_pos);
+}
+
+static ssize_t channel_read(struct file *filp, char __user *buf,
+	size_t count, loff_t *f_pos)
+{
+	return channel_read_gsi(filp, buf, count, f_pos);
+}
+
+static const struct file_operations channel_dev_fops = {
+	.owner = THIS_MODULE,
+	.open = channel_open,
+	.write = channel_write,
+	.read = channel_read,
+};
+
+static ssize_t set_skb_for_user(struct file *filp, char __user *buf,
+		       size_t size, loff_t *p_pos);
+
+static ssize_t get_skb_from_user(struct file *filp, const char __user *buf,
+		       size_t size, loff_t *f_pos);
+
+static const struct file_operations data_path_fops = {
+	.owner = THIS_MODULE,
+	.open = channel_open,
+	.read =	set_skb_for_user,
+	.write = get_skb_from_user,
+};
+
+
+/*
+ * This will create the char device named
+ * "<dev_name>_<index>" and allocate data
+ * FIFO(size mem_size).
+ * In this case, we will differentiate
+ * channel_dev_fops, which are used for
+ * regular data transmission
+ * in all the tests,and data_path_fops
+ * which will be used
+ * in DataPath tests for handling
+ * the SKB we will transfer
+ */
+int create_channel_device_by_type(
+			const int index,
+			const char *dev_name,
+			struct channel_dev **channel_dev_ptr,
+			size_t mem_size,
+			enum fops_type type)
+{
+	int ret;
+	char name[MAX_CHANNEL_NAME];
+	struct channel_dev *channel_dev = NULL;
+
+	scnprintf(name, sizeof(name), "%s_%d", dev_name, index);
+
+	IPATEST_DBG(":Creating channel %d device, name = %s.\n",
+		index, name);
+
+	/* Allocate memory for the device */
+	*channel_dev_ptr = kzalloc(sizeof(struct channel_dev), GFP_KERNEL);
+	if (NULL == *channel_dev_ptr) {
+		IPATEST_ERR("kzalloc err for channel dev\n");
+		ret = -ENOMEM;
+		goto create_channel_device_failure;
+	}
+
+	channel_dev = *channel_dev_ptr;
+
+	strlcpy(channel_dev->name, name, MAX_CHANNEL_NAME);
+
+	/* Allocate memory data buffer for the pipe */
+	IPATEST_DBG(":-----Allocate memory data buffer-----\n");
+	channel_dev->mem.size = mem_size;
+	test_alloc_mem(&channel_dev->mem);
+	if (NULL == channel_dev->mem.base) {
+		IPATEST_ERR("data fifo alloc fail\n");
+		ret = -ENOMEM;
+		goto create_channel_device_failure;
+	}
+	IPATEST_DBG(": data fifo: mem phys=0x%pa.virt=0x%px.\n",
+		&channel_dev->mem.phys_base, channel_dev->mem.base);
+	memset(channel_dev->mem.base, 0xbb, channel_dev->mem.size);
+
+	channel_dev->mem_buff_index = 0;
+
+	/* Add a pointer from the channel device to the test context info */
+	channel_dev->test = ipa_test;
+
+	channel_dev->class = class_create(THIS_MODULE, name);
+	if (IS_ERR(channel_dev->class)) {
+		IPATEST_ERR(":class_create() err.\n");
+		ret = -ENOMEM;
+		goto create_class_failure;
+	}
+
+	ret = alloc_chrdev_region(&channel_dev->dev_num, 0, 1, name);
+	if (ret) {
+		IPATEST_ERR("alloc_chrdev_region err.\n");
+		ret = -ENOMEM;
+		goto alloc_chrdev_failure;
+	}
+
+	channel_dev->dev = device_create(channel_dev->class, NULL,
+		channel_dev->dev_num, channel_dev, name);
+	if (IS_ERR(channel_dev->dev)) {
+		IPATEST_ERR("device_create err.\n");
+		ret = -ENODEV;
+		goto device_create_failure;
+	}
+	switch (type) {
+	case IPA_TEST_REG_CHANNEL:
+		cdev_init(&channel_dev->cdev, &channel_dev_fops);
+		break;
+	case IPA_TEST_DATA_PATH_TEST_CHANNEL:
+		cdev_init(&channel_dev->cdev, &data_path_fops);
+		break;
+	default:
+		IPATEST_ERR("Wrong fops type");
+		ret = -EINVAL;
+		goto invalid_type_err;
+	}
+	channel_dev->cdev.owner = THIS_MODULE;
+
+	ret = cdev_add(&channel_dev->cdev, channel_dev->dev_num, 1);
+	if (ret) {
+		IPATEST_ERR("cdev_add err=%d\n", -ret);
+		ret = -ENODEV;
+		goto cdev_add_failure;
+	}
+
+	if (!ret)
+		IPATEST_DBG("Channel device:%d, name:%s created, address:0x%px.\n",
+			index, name, channel_dev);
+
+	return 0;
+
+cdev_add_failure:
+	memset(&channel_dev->cdev, 0, sizeof(channel_dev->cdev));
+invalid_type_err:
+	device_destroy(channel_dev->class, channel_dev->dev_num);
+device_create_failure:
+	unregister_chrdev_region(channel_dev->dev_num, 1);
+alloc_chrdev_failure:
+	class_destroy(channel_dev->class);
+create_class_failure:
+	test_free_mem(&channel_dev->mem);
+create_channel_device_failure:
+	kfree(channel_dev);
+	IPATEST_ERR("Channel device %d, name %s creation FAILED.\n",
+		index, name);
+
+	return ret;
+}
+
+int create_channel_device(const int index,
+			  const char *dev_name,
+			  struct channel_dev **channel_dev_ptr,
+			  size_t mem_size) {
+	return create_channel_device_by_type(
+			index,
+			dev_name,
+			channel_dev_ptr,
+			mem_size,
+			IPA_TEST_REG_CHANNEL);
+}
+
+/*
+ * DataPath test definitions:
+ */
+
+#define MAX_TEST_SKB 15
+#define TIME_OUT_TIME 2000 /* 2 seconds */
+
+struct datapath_ctx {
+	struct mutex lock;
+	struct kfifo_rec_ptr_2 fifo;
+	struct completion write_done_completion;
+	struct completion ipa_receive_completion;
+};
+
+struct datapath_ctx *p_data_path_ctx;
+
+
+/*
+ * Inits the kfifo needed for the
+ * DataPath tests
+ */
+int datapath_ds_init(void)
+{
+	int res = 0;
+
+	p_data_path_ctx = kzalloc(sizeof(struct datapath_ctx), GFP_KERNEL);
+	if (!p_data_path_ctx) {
+		IPATEST_ERR("kzalloc returned error (%d)\n", res);
+		return res;
+	}
+	IPATEST_DBG("called.\n");
+
+	res = kfifo_alloc(&p_data_path_ctx->fifo
+			, (sizeof(struct sk_buff *)*MAX_TEST_SKB)
+			, GFP_KERNEL);
+	if (0 != res) {
+		IPATEST_ERR("kfifo_alloc returned error (%d)\n", res);
+		kfree(p_data_path_ctx);
+		return res;
+	}
+
+	mutex_init(&p_data_path_ctx->lock);
+	init_completion(&p_data_path_ctx->ipa_receive_completion);
+
+	IPATEST_DBG("completed.(%d)\n", res);
+
+	return res;
+}
+
+static struct sk_buff *datapath_create_skb(const char *buf, size_t size)
+{
+	struct sk_buff *skb;
+	unsigned char *data;
+	int err = 0;
+
+	IPATEST_DBG("allocating SKB, len=%zu", size);
+	skb = alloc_skb(size, GFP_KERNEL);
+	if (unlikely(!skb))
+		return NULL;
+	IPATEST_DBG("skb allocated, skb->len=%d", skb->len);
+	data = skb_put(skb, size);
+	if (unlikely(!data)) {
+		kfree_skb(skb);
+		return NULL;
+	}
+	IPATEST_DBG("skb put finish, skb->len=%d", skb->len);
+	skb->csum = csum_and_copy_from_user(
+			buf, data,
+			size, 0, &err);
+	if (err) {
+		kfree_skb(skb);
+		return NULL;
+	}
+	IPATEST_DBG("The following packet was created:\n");
+	print_buff(skb->data, size);
+	IPATEST_DBG("Exiting\n");
+
+	return skb;
+}
+
+static int datapath_read_data(void *element, int size)
+{
+	int res;
+
+	IPATEST_DBG("Entering\n");
+
+	mutex_lock(&p_data_path_ctx->lock);
+	reinit_completion(&p_data_path_ctx->ipa_receive_completion);
+	IPATEST_DBG("Init completion\n");
+	IPATEST_DBG("Checking if kfifo is empty\n");
+	if (kfifo_is_empty(&p_data_path_ctx->fifo)) {
+		IPATEST_DBG("kfifo is empty\n");
+		mutex_unlock(&p_data_path_ctx->lock);
+		IPATEST_DBG("wait_for_ipa_receive_completion\n");
+		res = wait_for_completion_timeout(
+			&p_data_path_ctx->ipa_receive_completion,
+			msecs_to_jiffies(TIME_OUT_TIME));
+		IPATEST_DBG("came back from wait_for_completion_timeout\n");
+		if (!res) {
+			IPATEST_ERR("Error in wait_for_ipa_receive_completion\n");
+			return -EINVAL;
+		}
+		IPATEST_DBG("locking lock\n");
+		mutex_lock(&p_data_path_ctx->lock);
+	}
+	res = kfifo_out(&p_data_path_ctx->fifo, element, size);
+	if (res != size) {
+		IPATEST_ERR("Error in taking out an element\n");
+		IPATEST_ERR("unlocking lock\n");
+		mutex_unlock(&p_data_path_ctx->lock);
+		return -EINVAL;
+	}
+	IPATEST_DBG("took %d bytes out\n", res);
+	IPATEST_DBG("unlocking lock\n");
+	IPATEST_DBG("Exiting\n");
+	mutex_unlock(&p_data_path_ctx->lock);
+	return res;
+}
+
+static int datapath_write_fifo(
+		void *element,
+		int size) {
+
+	int res;
+
+	IPATEST_DBG("Entering\n");
+	mutex_lock(&p_data_path_ctx->lock);
+	IPATEST_DBG("Mutex locked\n");
+	IPATEST_DBG("putting %px into fifo\n", element);
+	res = kfifo_in(&p_data_path_ctx->fifo, &element, size);
+	IPATEST_DBG("finished kfifo in\n");
+	if (res != size) {
+		IPATEST_ERR("Error in saving element\n");
+		return -EINVAL;
+	}
+	IPATEST_DBG("Mutex unlocked\n");
+
+	complete(&p_data_path_ctx->ipa_receive_completion);
+	IPATEST_DBG("Completed ipa_receive_completion\n");
+	mutex_unlock(&p_data_path_ctx->lock);
+	return 0;
+}
+
+/*
+ * Receives from the user space the buff,
+ * create an SKB, and send it through
+ * ipa_tx_dp that was received in the system
+ */
+static ssize_t get_skb_from_user(struct file *filp, const char __user *buf,
+		       size_t size, loff_t *f_pos) {
+
+	int res = 0;
+	struct sk_buff *skb;
+
+	IPATEST_DBG("Entering\n");
+	/* Copy the data from the user and transmit */
+	IPATEST_DBG("-----Copy the data from the user-----\n");
+
+	IPATEST_DBG("Creating SKB\n");
+
+	skb = datapath_create_skb(buf, size);
+	if (!skb)
+		return -EINVAL;
+	init_completion(&p_data_path_ctx->write_done_completion);
+	IPATEST_DBG(
+		"Starting transfer through ipa_tx_dp\n");
+	res = ipa_tx_dp(IPA_CLIENT_TEST_CONS, skb,
+			       NULL);
+	IPATEST_DBG("ipa_tx_dp res = %d.\n", res);
+	res = wait_for_completion_timeout(
+			&p_data_path_ctx->write_done_completion,
+			msecs_to_jiffies(TIME_OUT_TIME));
+	IPATEST_DBG("timeout result = %d", res);
+	if (!res)
+		return -EINVAL;
+	IPATEST_DBG("-----Exiting-----\n");
+
+	return size;
+}
+
+/*
+ * Sends the user space the next SKB
+ * that was received in the system
+ */
+
+static ssize_t set_skb_for_user(struct file *filp, char __user *buf,
+		       size_t size, loff_t *p_pos)
+{
+	int res;
+	struct sk_buff *p_skb;
+
+	IPATEST_DBG("Entering\n");
+	/* Copy the result to the user buffer */
+
+	IPATEST_DBG("datapath_read_data\n");
+	if (datapath_read_data(
+			(void *)&p_skb,
+			sizeof(struct sk_buff *)) < 0) {
+		IPATEST_ERR("error in datapath_read_data\n");
+		return -EINVAL;
+	}
+	print_buff(p_skb->data, size);
+	IPATEST_DBG("Copying data back to user\n");
+	res = copy_to_user(buf, p_skb->data, size);
+	kfree_skb(p_skb);
+	/* Return the number of bytes copied to the user */
+
+	return res;
+}
+
+static void datapath_ds_clean(void)
+{
+	kfifo_reset(&p_data_path_ctx->fifo);
+}
+
+/*
+ * Destroy the kfifo needed for the
+ * DataPath tests
+ */
+
+static void datapath_exit(void)
+{
+	kfifo_free(&p_data_path_ctx->fifo);
+	/* freeing kfifo */
+	kfree(p_data_path_ctx);
+	p_data_path_ctx = NULL;
+}
+
+/*
+ * CB func. for the IPA_WRITE_DONE
+ * event. Used in IpaTxDpTest
+ */
+
+static void notify_ipa_write_done(
+		void *priv,
+		enum ipa_dp_evt_type evt,
+		unsigned long data) {
+
+	IPATEST_DBG("Entering function\n");
+
+	if (evt == IPA_WRITE_DONE) {
+		IPATEST_DBG("evt IPA_WRITE_DONE\n");
+		IPATEST_DBG("Printing received buff from IPA\n");
+		print_buff(
+			((struct sk_buff *)data)->data,
+			((struct sk_buff *)data)->len);
+
+		kfree_skb((struct sk_buff *)data);
+		complete(&p_data_path_ctx->write_done_completion);
+
+	} else {
+		IPATEST_DBG("Error, wrong event %d\n", evt);
+	}
+}
+
+/*
+ * CB func. for the IPA_RECEIVE
+ * event. Used in IPAToAppsTest
+ */
+
+static void notify_ipa_received(
+		void *priv,
+		enum ipa_dp_evt_type evt,
+		unsigned long data){
+
+	struct sk_buff *p_skb = (struct sk_buff *)data;
+
+	IPATEST_DBG("Entering function\n");
+
+	if (evt == IPA_RECEIVE) {
+		IPATEST_DBG("evt IPA_RECEIVE\n");
+		IPATEST_DBG("Printing received buff from IPA\n");
+		print_buff(p_skb->data, p_skb->len);
+		datapath_write_fifo(p_skb, sizeof(struct sk_buff *));
+	} else {
+		IPATEST_ERR("Error: wrong event %d", evt);
+	}
+}
+
+static void ipa_test_gsi_evt_ring_err_cb(struct gsi_evt_err_notify *notify)
+{
+	if (notify) {
+		switch (notify->evt_id) {
+		case GSI_EVT_OUT_OF_BUFFERS_ERR:
+			IPATEST_ERR("Received GSI_EVT_OUT_OF_BUFFERS_ERR\n");
+			break;
+		case GSI_EVT_OUT_OF_RESOURCES_ERR:
+			IPATEST_ERR("Received GSI_EVT_OUT_OF_RESOURCES_ERR\n");
+			break;
+		case GSI_EVT_UNSUPPORTED_INTER_EE_OP_ERR:
+			IPATEST_ERR("Received GSI_EVT_UNSUPPORTED_INTER_EE_OP_ERR\n");
+			break;
+		case GSI_EVT_EVT_RING_EMPTY_ERR:
+			IPATEST_ERR("Received GSI_EVT_EVT_RING_EMPTY_ERR\n");
+			break;
+		default:
+			IPATEST_ERR("Unexpected err evt: %d\n", notify->evt_id);
+		}
+	}
+	return;
+}
+
+static void ipa_test_gsi_chan_err_cb(struct gsi_chan_err_notify *notify)
+{
+	if (notify) {
+		switch (notify->evt_id) {
+		case GSI_CHAN_INVALID_TRE_ERR:
+			IPATEST_ERR("Received GSI_CHAN_INVALID_TRE_ERR\n");
+			break;
+		case GSI_CHAN_NON_ALLOCATED_EVT_ACCESS_ERR:
+			IPATEST_ERR("Received GSI_CHAN_NON_ALLOCATED_EVT_ACCESS_ERR\n");
+			break;
+		case GSI_CHAN_OUT_OF_BUFFERS_ERR:
+			IPATEST_ERR("Received GSI_CHAN_OUT_OF_BUFFERS_ERR\n");
+			break;
+		case GSI_CHAN_OUT_OF_RESOURCES_ERR:
+			IPATEST_ERR("Received GSI_CHAN_OUT_OF_RESOURCES_ERR\n");
+			break;
+		case GSI_CHAN_UNSUPPORTED_INTER_EE_OP_ERR:
+			IPATEST_ERR("Received GSI_CHAN_UNSUPPORTED_INTER_EE_OP_ERR\n");
+			break;
+		case GSI_CHAN_HWO_1_ERR:
+			IPATEST_ERR("Received GSI_CHAN_HWO_1_ERR\n");
+			break;
+		default:
+			IPATEST_ERR("Unexpected err ch: %d\n", notify->evt_id);
+		}
+	}
+	return;
+}
+
+static void ipa_test_gsi_irq_notify_cb(struct gsi_chan_xfer_notify *notify)
+{
+	IPATEST_DBG("ipa_test_gsi_irq_notify_cb: channel 0x%px xfer 0x%px\n", notify->chan_user_data, notify->xfer_user_data);
+	IPATEST_DBG("ipa_test_gsi_irq_notify_cb: event %d notified\n", notify->evt_id);
+	IPATEST_DBG("ipa_test_gsi_irq_notify_cb: bytes_xfered %d\n", notify->bytes_xfered);
+}
+
+int connect_ipa_to_apps(struct test_endpoint_sys *rx_ep,
+			   enum ipa_client_type client,
+			   u32 pipe_index,
+			   unsigned long ipa_gsi_hdl)
+{
+	int res = 0;
+
+	dma_addr_t dma_addr;
+	const struct ipa_gsi_ep_config *gsi_ep_config;
+
+	memset(&rx_ep->gsi_evt_ring_props, 0, sizeof(rx_ep->gsi_evt_ring_props));
+	rx_ep->gsi_evt_ring_props.intf = GSI_EVT_CHTYPE_GPI_EV;
+	rx_ep->gsi_evt_ring_props.intr = GSI_INTR_IRQ;
+	rx_ep->gsi_evt_ring_props.re_size =
+		GSI_EVT_RING_RE_SIZE_16B;
+
+	rx_ep->gsi_evt_ring_props.ring_len = GSI_EVT_RING_LEN;
+	rx_ep->gsi_evt_ring_props.ring_base_vaddr =
+		dma_alloc_coherent(ipa3_get_pdev(), GSI_EVT_RING_LEN,
+		&dma_addr, 0);
+	rx_ep->gsi_evt_ring_props.ring_base_addr = dma_addr;
+
+	rx_ep->gsi_evt_ring_props.int_modt = 3200; //0.1s under 32KHz clock
+	rx_ep->gsi_evt_ring_props.int_modc = 1;
+	rx_ep->gsi_evt_ring_props.rp_update_addr = 0;
+	rx_ep->gsi_evt_ring_props.exclusive = true;
+	rx_ep->gsi_evt_ring_props.err_cb = ipa_test_gsi_evt_ring_err_cb;
+	rx_ep->gsi_evt_ring_props.user_data = NULL;
+
+	res = gsi_alloc_evt_ring(&rx_ep->gsi_evt_ring_props, ipa_gsi_hdl,
+		&rx_ep->gsi_evt_ring_hdl);
+	if (res != GSI_STATUS_SUCCESS) {
+		IPATEST_ERR("gsi_alloc_evt_ring failed %d\n", res);
+		return -EFAULT;
+	}
+
+	memset(&rx_ep->gsi_channel_props, 0,
+		sizeof(rx_ep->gsi_channel_props));
+	rx_ep->gsi_channel_props.prot = GSI_CHAN_PROT_GPI;
+	rx_ep->gsi_channel_props.dir = GSI_CHAN_DIR_FROM_GSI;
+	gsi_ep_config = ipa_get_gsi_ep_info(client);
+	if (!gsi_ep_config) {
+		IPATEST_ERR("invalid gsi_ep_config\n");
+		return -EFAULT;
+	}
+	rx_ep->gsi_channel_props.ch_id =
+		gsi_ep_config->ipa_gsi_chan_num;
+	rx_ep->gsi_channel_props.evt_ring_hdl = rx_ep->gsi_evt_ring_hdl;
+	rx_ep->gsi_channel_props.re_size = GSI_CHAN_RE_SIZE_16B;
+
+	rx_ep->gsi_channel_props.ring_len = GSI_CHANNEL_RING_LEN;
+	rx_ep->gsi_channel_props.ring_base_vaddr =
+		dma_alloc_coherent(ipa3_get_pdev(), GSI_CHANNEL_RING_LEN,
+		&dma_addr, 0);
+	if (!rx_ep->gsi_channel_props.ring_base_vaddr) {
+		IPATEST_ERR("connect_ipa_to_apps: falied to alloc GSI ring\n");
+		return -EFAULT;
+	}
+
+	rx_ep->gsi_channel_props.ring_base_addr = dma_addr;
+	rx_ep->gsi_channel_props.use_db_eng = GSI_CHAN_DIRECT_MODE;
+	rx_ep->gsi_channel_props.max_prefetch = GSI_ONE_PREFETCH_SEG;
+	rx_ep->gsi_channel_props.low_weight = 1;
+	rx_ep->gsi_channel_props.chan_user_data = rx_ep;
+	if (ipa_get_hw_type() >= IPA_HW_v4_9)
+		rx_ep->gsi_channel_props.db_in_bytes = 1;
+
+	rx_ep->gsi_channel_props.err_cb = ipa_test_gsi_chan_err_cb;
+	rx_ep->gsi_channel_props.xfer_cb = ipa_test_gsi_irq_notify_cb;
+	res = gsi_alloc_channel(&rx_ep->gsi_channel_props, ipa_gsi_hdl,
+		&rx_ep->gsi_chan_hdl);
+	if (res != GSI_STATUS_SUCCESS) {
+		IPATEST_ERR("gsi_alloc_channel failed %d\n", res);
+		return -EFAULT;
+	}
+	rx_ep->gsi_valid = true;
+
+	res = ipa3_sys_update_gsi_hdls(pipe_index, rx_ep->gsi_chan_hdl, rx_ep->gsi_evt_ring_hdl);
+	if (res) {
+		IPATEST_ERR("ipa_sys_update_gsi_hdls failed %d\n", res);
+		return -EFAULT;
+	}
+
+	res = gsi_start_channel(rx_ep->gsi_chan_hdl);
+	if (res != GSI_STATUS_SUCCESS) {
+		IPATEST_ERR("gsi_start_channel failed %d\n", res);
+		return -EFAULT;
+	}
+
+	IPATEST_DBG("setting channel to polling mode\n");
+	res = gsi_config_channel_mode(rx_ep->gsi_chan_hdl, GSI_CHAN_MODE_POLL);
+	if (res != GSI_STATUS_SUCCESS) {
+		IPATEST_ERR("gsi_config_channel_mode failed %d\n", res);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int connect_apps_to_ipa(struct test_endpoint_sys *tx_ep,
+			   enum ipa_client_type client,
+			   u32 pipe_index,
+			   struct ipa_mem_buffer *desc_fifo,
+			   unsigned long ipa_gsi_hdl)
+{
+	int res = 0;
+	dma_addr_t dma_addr;
+	const struct ipa_gsi_ep_config *gsi_ep_config;
+
+	memset(&tx_ep->gsi_evt_ring_props, 0, sizeof(tx_ep->gsi_evt_ring_props));
+	tx_ep->gsi_evt_ring_props.intf = GSI_EVT_CHTYPE_GPI_EV;
+	tx_ep->gsi_evt_ring_props.intr = GSI_INTR_IRQ;
+	tx_ep->gsi_evt_ring_props.re_size =
+		GSI_EVT_RING_RE_SIZE_16B;
+
+	tx_ep->gsi_evt_ring_props.ring_len = GSI_EVT_RING_LEN;
+	tx_ep->gsi_evt_ring_props.ring_base_vaddr =
+		dma_alloc_coherent(ipa3_get_pdev(), GSI_EVT_RING_LEN,
+		&dma_addr, 0);
+	tx_ep->gsi_evt_ring_props.ring_base_addr = dma_addr;
+
+	tx_ep->gsi_evt_ring_props.int_modt = 3200; //0.1s under 32KHz clock
+	tx_ep->gsi_evt_ring_props.int_modc = 1;
+	tx_ep->gsi_evt_ring_props.rp_update_addr = 0;
+	tx_ep->gsi_evt_ring_props.exclusive = true;
+	tx_ep->gsi_evt_ring_props.err_cb = ipa_test_gsi_evt_ring_err_cb;
+	tx_ep->gsi_evt_ring_props.user_data = NULL;
+
+	res = gsi_alloc_evt_ring(&tx_ep->gsi_evt_ring_props, ipa_gsi_hdl,
+		&tx_ep->gsi_evt_ring_hdl);
+	if (res != GSI_STATUS_SUCCESS) {
+		IPATEST_ERR("gsi_alloc_evt_ring failed %d\n", res);
+		return -EFAULT;
+	}
+
+	memset(&tx_ep->gsi_channel_props, 0, sizeof(tx_ep->gsi_channel_props));
+	tx_ep->gsi_channel_props.prot = GSI_CHAN_PROT_GPI;
+	tx_ep->gsi_channel_props.dir = GSI_CHAN_DIR_TO_GSI;
+	gsi_ep_config = ipa_get_gsi_ep_info(client);
+	if (!gsi_ep_config) {
+		IPATEST_ERR("invalid gsi_ep_config\n");
+		return -EFAULT;
+	}
+	tx_ep->gsi_channel_props.ch_id =
+		gsi_ep_config->ipa_gsi_chan_num;
+	tx_ep->gsi_channel_props.evt_ring_hdl = tx_ep->gsi_evt_ring_hdl;
+	tx_ep->gsi_channel_props.re_size = GSI_CHAN_RE_SIZE_16B;
+
+	tx_ep->gsi_channel_props.ring_len = GSI_CHANNEL_RING_LEN;
+	tx_ep->gsi_channel_props.ring_base_vaddr =
+		dma_alloc_coherent(ipa3_get_pdev(), GSI_CHANNEL_RING_LEN,
+		&dma_addr, 0);
+	if (!tx_ep->gsi_channel_props.ring_base_vaddr) {
+		IPATEST_ERR("connect_apps_to_ipa: falied to alloc GSI ring\n");
+		return -EFAULT;
+	}
+
+	tx_ep->gsi_channel_props.ring_base_addr = dma_addr;
+	tx_ep->gsi_channel_props.use_db_eng = GSI_CHAN_DIRECT_MODE;
+	tx_ep->gsi_channel_props.max_prefetch = GSI_ONE_PREFETCH_SEG;
+	tx_ep->gsi_channel_props.low_weight = 1;
+	tx_ep->gsi_channel_props.chan_user_data = tx_ep;
+	if (ipa_get_hw_type() >= IPA_HW_v4_9)
+		tx_ep->gsi_channel_props.db_in_bytes = 1; 
+
+	tx_ep->gsi_channel_props.err_cb = ipa_test_gsi_chan_err_cb;
+	tx_ep->gsi_channel_props.xfer_cb = ipa_test_gsi_irq_notify_cb;
+	res = gsi_alloc_channel(&tx_ep->gsi_channel_props, ipa_gsi_hdl,
+		&tx_ep->gsi_chan_hdl);
+	if (res != GSI_STATUS_SUCCESS) {
+		IPATEST_ERR("gsi_alloc_channel failed %d\n", res);
+		return -EFAULT;
+	}
+	tx_ep->gsi_valid = true;
+
+	res = ipa3_sys_update_gsi_hdls(pipe_index, tx_ep->gsi_chan_hdl, tx_ep->gsi_evt_ring_hdl);
+	if (res) {
+		IPATEST_ERR("ipa_sys_update_gsi_hdls failed %d\n", res);
+		return -EFAULT;
+	}
+
+	res = gsi_start_channel(tx_ep->gsi_chan_hdl);
+	if (res != GSI_STATUS_SUCCESS) {
+		IPATEST_ERR("gsi_start_channel failed %d\n", res);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int configure_ipa_endpoint(struct ipa_ep_cfg *ipa_ep_cfg,
+			   enum ipa_mode_type mode)
+{
+	const char *DEFAULT_ROUTING_TABLE_NAME = "LAN";
+	const enum ipa_client_type DEFAULT_CLIENT = IPA_CLIENT_TEST4_CONS;
+	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_rt_rule_add *rt_rule_entry;
+	struct ipa_ioc_get_rt_tbl rt_lookup;
+
+	memset(ipa_ep_cfg, 0, sizeof(*ipa_ep_cfg));
+	/* Configure mode */
+	ipa_ep_cfg->mode.mode = mode;
+	/* Add default routing rule */
+	rt_rule = kzalloc(sizeof(struct ipa_ioc_add_rt_rule) +
+			1 * sizeof(struct ipa_rt_rule_add), GFP_KERNEL);
+	if (!rt_rule) {
+		IPATEST_ERR("Allocation failure.\n");
+		return -EINVAL;
+	}
+	rt_rule->commit = 1;
+	rt_rule->num_rules = 1;
+	rt_rule->ip = IPA_IP_v4;
+	strlcpy(rt_rule->rt_tbl_name,
+			DEFAULT_ROUTING_TABLE_NAME,
+			IPA_RESOURCE_NAME_MAX);
+	rt_rule_entry = &rt_rule->rules[0];
+	rt_rule_entry->at_rear = 1;
+	rt_rule_entry->rule.dst = DEFAULT_CLIENT;
+	/* Issuing a routing rule without
+	 * any equations will cause a default rule
+	   which catches every packet and sends it
+	   to the default endpoint. */
+	if (ipa_add_rt_rule(rt_rule)) {
+		IPATEST_ERR("ipa_add_rt_rule() failure.\n");
+	}
+	IPATEST_DBG("rt rule hdl1=%x.\n", rt_rule_entry->rt_rule_hdl);
+	/*	At this point, there is a routing table in memory,
+		with one defalut rule.
+		user space test application will enter more valid
+		rules the default rule
+		must be last on the list.
+		Get a handle to the routing table which holds
+		the added rule. This will
+		also increment an internal reference count. */
+	memset(&rt_lookup, 0, sizeof(struct ipa_ioc_get_rt_tbl));
+	rt_lookup.ip = IPA_IP_v4;
+	strlcpy(rt_lookup.name,
+			DEFAULT_ROUTING_TABLE_NAME,
+			IPA_RESOURCE_NAME_MAX);
+	if (ipa3_get_rt_tbl(&rt_lookup)) {
+		IPATEST_ERR("ipa_get_rt_tbl() failure.\n");
+	}
+	ipa_ep_cfg->route.rt_tbl_hdl = rt_lookup.hdl;
+	/* Now release the routing table hdl. This code assumes
+	   that routing table
+	   will continue to exist when the endpoint
+	   connection is requested. */
+	if (ipa_put_rt_tbl(rt_lookup.hdl)) {
+		IPATEST_ERR("ipa_put_rt_tbl() failure.\n");
+	}
+	return 0;
+}
+
+/*
+ * Configures the system as follows:
+ * This configuration is for one input pipe
+ * and one output pipe where both are USB1
+ * /dev/to_ipa_0 -> MEM -> IPA
+ * -> MEM -> /dev/from_ipa_0
+ * Those client will be configured in DMA mode thus
+ * no Header removal/insertion will be
+ * made on their data.
+*/
+int configure_system_1(void)
+{
+	int res = 0;
+	struct ipa_ep_cfg ipa_ep_cfg;
+
+	struct ipa_sys_connect_params sys_in;
+	unsigned long ipa_gsi_hdl;
+	u32 ipa_pipe_num;
+
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	IPATEST_DBG("Configure_system_1 was called\n");
+
+	/* Connect IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_CONS;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+	/* Prepare EP configuration details */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.mode.mode = IPA_DMA;
+	ipa_ep_cfg.mode.dst = IPA_CLIENT_TEST_CONS;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[0]->mem,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+fail:
+	/* cleanup and tear down goes here*/
+	return res;
+}
+
+/*
+ Configures the system with one input to IPA and 2 outputs.
+ /dev/to_ipa_0 -> MEM -> GSI -> IPA |-> GSI
+ -> MEM -> /dev/from_ipa_0
+|-> GSI -> MEM -> /dev/from_ipa_1
+*/
+int configure_system_2(void)
+{
+	int res = 0;
+	struct ipa_ep_cfg ipa_ep_cfg;
+
+	struct ipa_sys_connect_params sys_in;
+	unsigned long ipa_gsi_hdl;
+	u32 ipa_pipe_num;
+
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+
+
+	/* Connect first Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST2_CONS;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST2_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Connect second Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST3_CONS;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[1]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[1]->ep,
+				  IPA_CLIENT_TEST3_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Connect third (Default) Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST4_CONS;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[2]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[2]->ep,
+			IPA_CLIENT_TEST4_CONS,
+			ipa_pipe_num,
+			ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[0]->mem,
+				  ipa_gsi_hdl);
+
+
+	if (res)
+		goto fail;
+
+	/* Connect Tx GSI -> IPA */
+	/* Prepare an endpoint configuration structure */
+	res = configure_ipa_endpoint(&ipa_ep_cfg, IPA_BASIC);
+	if (res)
+		goto fail;
+
+	/* configure header removal on Tx */
+	ipa_ep_cfg.hdr.hdr_len = ETH_HLEN;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST2_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[1]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[1]->ep,
+				  IPA_CLIENT_TEST2_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[1]->mem,
+				  ipa_gsi_hdl);
+
+
+	if (res)
+		goto fail;
+
+fail:
+	/* cleanup and tear down goes here */
+	return res;
+}
+
+/*Configuration used for Header Insertion Tests*/
+int configure_system_5(void)
+{
+	int res = 0;
+	struct ipa_ep_cfg ipa_ep_cfg;
+
+	struct ipa_sys_connect_params sys_in;
+	unsigned long ipa_gsi_hdl;
+	u32 ipa_pipe_num;
+
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+
+	/* configure header Insertion on Tx */
+
+/*	ipa_ep_cfg.hdr.hdr_len  = IPA_TEST_DMUX_HEADER_LENGTH;
+ !< Header length in bytes to be added/removed.
+	Assuming heaser len is constant per endpoint.
+	Valid for both Input and Output Pipes
+	Length of Header to add / to remove
+	ipa_ep_cfg.hdr.hdr_additional_const_len = 0;
+	!< Defines the constant length that should be added
+	to the payload length in order for IPA to update
+	correctly the length field within the header
+	(valid only in case Hdr_Ofst_Pkt_Size_Valid=1)
+	Valid for Output Pipes (IPA Producer)
+	ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 0;
+	!< 0: Hdr_Ofst_Pkt_Size  value is invalid, i.e.,
+	no length field within the inserted header
+	1: Hdr_Ofst_Pkt_Size  value is valid, i.e.,
+	a packet length field resides within the header
+	Valid for Output Pipes (IPA Producer)
+	ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
+	!< Offset within header in which packet size
+	reside. Upon Header Insertion, IPA will update this
+	field within the header with the packet length .
+	Assumption is that header length field size is
+	constant and is 2Bytes Valid for Output Pipes (IPA Producer)
+	ipa_ep_cfg.hdr.hdr_a5_mux = 0;
+	0: Do not insert APPS Mux Header
+	1: Insert APPS Mux Header
+	!< Determines whether APPS Mux header should be
+	added to the packet. This bit is valid only when
+	Hdr_En=01(Header Insertion) SW should set this bit
+	for IPA-to-APPS pipes.
+	0: Do not insert APPS Mux Header
+	1: Insert APPS Mux Header
+	Valid for Output Pipes (IPA Producer) */
+
+
+
+	/* Connect IPA -> first Rx GSI */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.hdr.hdr_len =
+			IPA_TEST_HDI_RMNET_HEADER_LENGTH;
+	/* Length of Header to add / to remove */
+	ipa_ep_cfg.hdr.hdr_additional_const_len =
+			IPA_TEST_HDI_RMNET_ADD_CONST_LENGTH;
+	/* constant length that should be added to the payload
+	 * length or IPA to update correctly the length
+	 *  field within the header */
+	ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid
+		= IPA_TEST_HDI_RMNET_LENGTH_FIELD_OFFSET_VALID;
+	/*0: Hdr_Ofst_Pkt_Size  value is invalid, i.e.,
+	  no length field within the inserted header
+	  1: Hdr_Ofst_Pkt_Size  value is valid, i.e.,
+	  a packet length field resides within the header*/
+	ipa_ep_cfg.hdr.hdr_ofst_pkt_size
+		= IPA_TEST_HDI_RMNET_LENGTH_FIELD_OFFSET;
+	/*	Offset within header in which packet size reside.
+		Upon Header Insertion, IPA will update this field
+		within the header with the packet length .
+		Assumption is that header length field size
+		is constant and is 2Bytes */
+
+	/* Connect first Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST2_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST2_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.hdr.hdr_len = IPA_TEST_HDI_802_HEADER_LENGTH;
+	/*Length of Header to add / to remove*/
+	ipa_ep_cfg.hdr.hdr_additional_const_len
+		= IPA_TEST_HDI_802_ADD_CONST_LENGTH;
+	/* constant length that should be added
+	 * to the payload length
+	   or IPA to update correctly the
+	   length field within the header */
+	ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid
+		= IPA_TEST_HDI_802_LENGTH_FIELD_OFFSET_VALID;
+	/*0: Hdr_Ofst_Pkt_Size  value is invalid, i.e.,
+	 no length field within the inserted header
+	 1: Hdr_Ofst_Pkt_Size  value is valid, i.e.
+	  a packet length field resides within the header*/
+	ipa_ep_cfg.hdr.hdr_ofst_pkt_size
+		= IPA_TEST_HDI_802_LENGTH_FIELD_OFFSET;
+	/* Offset within header in which packet size reside.
+	   Upon Header Insertion, IPA will update this field
+	   within the header with the packet length.
+	   Assumption is that header length field size is constant
+	   and is 2Bytes */
+		/* Connect second Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST3_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl,
+				&ipa_pipe_num,
+				&from_ipa_devs[1]->ipa_client_hdl,
+				false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[1]->ep,
+				  IPA_CLIENT_TEST3_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Connect IPA -> third (default) Rx GSI */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.hdr.hdr_len
+		= IPA_TEST_HDI_802_HEADER_LENGTH;
+	/* Length of Header to add / to remove */
+	ipa_ep_cfg.hdr.hdr_additional_const_len
+		= IPA_TEST_HDI_802_ADD_CONST_LENGTH+1;
+	/*  constant length that should be
+	 *  added to the payload length
+		or IPA to update correctly the length
+		field within the header */
+	ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid
+		= IPA_TEST_HDI_802_LENGTH_FIELD_OFFSET_VALID;
+	/* 0: Hdr_Ofst_Pkt_Size  value is invalid, i.e.,
+	   no length field within the inserted header
+	   1: Hdr_Ofst_Pkt_Size  value is valid, i.e.,
+	   a packet length field resides within the header */
+	ipa_ep_cfg.hdr.hdr_ofst_pkt_size
+		= IPA_TEST_HDI_802_LENGTH_FIELD_OFFSET;
+	/* Offset within header in which packet size reside.
+	 * Upon Header Insertion, IPA will update this field
+	 * within the header with the packet length .
+	 * Assumption is that header length field size is constant
+	 * and is 2Bytes */
+	/* Connect third (Default) Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST4_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl,
+			&ipa_pipe_num, &from_ipa_devs[2]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[2]->ep,
+				  IPA_CLIENT_TEST4_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+
+	if (res)
+		goto fail;
+
+	/* Connect Tx GSI -> IPA */
+	/* Prepare an endpoint configuration structure */
+	res = configure_ipa_endpoint(&ipa_ep_cfg, IPA_BASIC);
+	if (res)
+		goto fail;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[0]->mem,
+				  ipa_gsi_hdl);
+
+	if (res)
+		goto fail;
+
+fail:
+	/* cleanup and tear down goes here */
+	return res;
+}
+
+/*Configuration Used for USB Integration (on R3PC) */
+int configure_system_6(void)
+{
+	int res = 0;
+	struct ipa_ep_cfg ipa_ep_cfg;
+	struct ipa_sys_connect_params sys_in;
+	unsigned long ipa_gsi_hdl;
+	u32 ipa_pipe_num;
+
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	/* Connect first Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST2_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+	res = connect_ipa_to_apps(&from_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST2_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	/* Prepare an endpoint configuration structure */
+	ipa_ep_cfg.mode.mode = IPA_BASIC;
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST2_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST2_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[0]->mem,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+fail:
+	/* cleanup and tear down goes here */
+	return res;
+}
+
+
+/*
+ Configures the system as follows:
+ This configuration is for 4 input pipes and 3 output pipes:
+ /dev/to_ipa_0 -> MEM -> GSI ->
+  * IPA -> GSI -> MEM -> /dev/from_ipa_0
+ /dev/to_ipa_1 -> MEM -> GSI ->
+  * IPA -> GSI -> MEM -> /dev/from_ipa_1
+ /dev/to_ipa_2 -> MEM -> GSI ->
+  * IPA -> GSI -> MEM -> /dev/from_ipa_0
+ /dev/to_ipa_3 -> MEM -> GSI ->
+  * IPA -> GSI -> MEM -> /dev/from_ipa_2
+ to_ipa_1, to_ipa_2, from_ipa_0 &
+ from_ipa_2 transfer TLP aggregated packets
+ to_ipa_0, to_ipa_3 & from_ipa_1 transfer raw packets
+*/
+int configure_system_8(void)
+{
+	int res = 0;
+	struct ipa_ep_cfg ipa_ep_cfg;
+
+	struct ipa_sys_connect_params sys_in;
+	unsigned long ipa_gsi_hdl;
+	u32 ipa_pipe_num;
+
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	IPATEST_DBG("Configure_system_8 was called\n");
+
+	/* Setup GSI pipes */
+	to_ipa_devs[0]->dma_ep.src_pipe_index = 4;
+	to_ipa_devs[0]->dma_ep.dest_pipe_index = 5;
+	to_ipa_devs[1]->dma_ep.src_pipe_index = 6;
+	to_ipa_devs[1]->dma_ep.dest_pipe_index = 7;
+	to_ipa_devs[2]->dma_ep.src_pipe_index = 8;
+	to_ipa_devs[2]->dma_ep.dest_pipe_index = 9;
+	to_ipa_devs[3]->dma_ep.src_pipe_index = 10;
+	to_ipa_devs[3]->dma_ep.dest_pipe_index = 11;
+
+	from_ipa_devs[0]->dma_ep.src_pipe_index = 14;
+	from_ipa_devs[0]->dma_ep.dest_pipe_index = 15;
+	from_ipa_devs[1]->dma_ep.src_pipe_index = 16;
+	from_ipa_devs[1]->dma_ep.dest_pipe_index = 17;
+	from_ipa_devs[2]->dma_ep.src_pipe_index = 18;
+	from_ipa_devs[2]->dma_ep.dest_pipe_index = 19;
+	/* configure aggregation on Tx */
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_TLP;
+	ipa_ep_cfg.aggr.aggr_byte_limit = 1;
+	ipa_ep_cfg.aggr.aggr_time_limit = 0;
+
+	/* Connect IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Connect IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST3_CONS;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[1]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[1]->ep,
+				  IPA_CLIENT_TEST3_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* configure aggregation on Tx */
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_TLP;
+	ipa_ep_cfg.aggr.aggr_byte_limit = 1;
+	ipa_ep_cfg.aggr.aggr_time_limit = 30;
+	if (ipa_get_hw_type() >= IPA_HW_v4_2)
+		ipa_ep_cfg.aggr.aggr_time_limit *= 1000;
+
+	/* Connect IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST2_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[2]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[2]->ep,
+			IPA_CLIENT_TEST2_CONS,
+			ipa_pipe_num,
+			ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Prepare EP configuration details */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.mode.mode = IPA_DMA;
+	ipa_ep_cfg.mode.dst = IPA_CLIENT_TEST_CONS;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST3_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST3_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[0]->mem,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* configure deaggregation on Rx */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.mode.mode = IPA_DMA;
+	ipa_ep_cfg.mode.dst = IPA_CLIENT_TEST3_CONS;
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_DEAGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_TLP;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[1]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[1]->ep,
+				  IPA_CLIENT_TEST_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[1]->mem,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* configure deaggregation on Rx */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.mode.mode = IPA_DMA;
+	ipa_ep_cfg.mode.dst = IPA_CLIENT_TEST_CONS;
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_DEAGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_TLP;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST2_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[2]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[2]->ep,
+				  IPA_CLIENT_TEST2_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[2]->mem,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Prepare EP configuration details */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.mode.mode = IPA_DMA;
+	ipa_ep_cfg.mode.dst = IPA_CLIENT_TEST2_CONS;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST4_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[3]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[3]->ep,
+			IPA_CLIENT_TEST4_PROD,
+			ipa_pipe_num,
+			&to_ipa_devs[3]->mem,
+			ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+fail:
+	/* cleanup and tear down goes here */
+	return res;
+}
+
+
+/*
+ Configures the system as follows:
+ This configuration is for 4 input pipes and 3 output pipes:
+ /dev/to_ipa_0 -> MEM -> GSI
+  * -> IPA -> GSI -> MEM -> /dev/from_ipa_0
+ /dev/to_ipa_1 -> MEM -> GSI
+  * -> IPA -> GSI -> MEM -> /dev/from_ipa_1
+ /dev/to_ipa_2 -> MEM -> GSI
+  * -> IPA -> GSI -> MEM -> /dev/from_ipa_0
+ /dev/to_ipa_3 -> MEM -> GSI
+  * -> IPA -> GSI -> MEM -> /dev/from_ipa_2
+ to_ipa_1, to_ipa_2, from_ipa_0 &
+ from_ipa_2 transfer MBIM aggregated packets
+ to_ipa_0, to_ipa_3 & from_ipa_1 transfer raw packets
+*/
+int configure_system_9(void)
+{
+	int res = 0;
+	struct ipa_ep_cfg ipa_ep_cfg;
+	enum ipa_aggr_mode mode;
+	struct ipa_sys_connect_params sys_in;
+	unsigned long ipa_gsi_hdl;
+	u32 ipa_pipe_num;
+
+	mode = IPA_MBIM_AGGR;
+	res = ipa_set_aggr_mode(mode);
+	if (res)
+		goto fail;
+	res = ipa_set_single_ndp_per_mbim(true);
+	if (res)
+		goto fail;
+
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	IPATEST_DBG("Configure_system_9 was called\n");
+
+	/* Setup GSI pipes */
+	to_ipa_devs[0]->dma_ep.src_pipe_index = 4;
+	to_ipa_devs[0]->dma_ep.dest_pipe_index = 5;
+	to_ipa_devs[1]->dma_ep.src_pipe_index = 6;
+	to_ipa_devs[1]->dma_ep.dest_pipe_index = 7;
+	to_ipa_devs[2]->dma_ep.src_pipe_index = 8;
+	to_ipa_devs[2]->dma_ep.dest_pipe_index = 9;
+	to_ipa_devs[3]->dma_ep.src_pipe_index = 10;
+	to_ipa_devs[3]->dma_ep.dest_pipe_index = 11;
+
+	from_ipa_devs[0]->dma_ep.src_pipe_index = 14;
+	from_ipa_devs[0]->dma_ep.dest_pipe_index = 15;
+	from_ipa_devs[1]->dma_ep.src_pipe_index = 16;
+	from_ipa_devs[1]->dma_ep.dest_pipe_index = 17;
+	from_ipa_devs[2]->dma_ep.src_pipe_index = 18;
+	from_ipa_devs[2]->dma_ep.dest_pipe_index = 19;
+
+	/* configure aggregation on Tx */
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_MBIM_16;
+	ipa_ep_cfg.aggr.aggr_byte_limit = 1;
+	ipa_ep_cfg.aggr.aggr_time_limit = 0;
+	ipa_ep_cfg.hdr.hdr_len = 1;
+
+	/* Connect IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Connect IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST3_CONS;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[1]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[1]->ep,
+				  IPA_CLIENT_TEST3_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* configure aggregation on Tx */
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_MBIM_16;
+	ipa_ep_cfg.aggr.aggr_byte_limit = 1;
+	ipa_ep_cfg.aggr.aggr_time_limit = 30;
+	if (ipa_get_hw_type() >= IPA_HW_v4_2)
+		ipa_ep_cfg.aggr.aggr_time_limit *= 1000;
+	ipa_ep_cfg.hdr.hdr_len = 1;
+
+	/* Connect IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST2_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[2]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[2]->ep,
+				  IPA_CLIENT_TEST2_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Prepare EP configuration details */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.mode.mode = IPA_DMA;
+	ipa_ep_cfg.mode.dst = IPA_CLIENT_TEST_CONS;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST3_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST3_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[0]->mem,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* configure deaggregation on Rx */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.mode.mode = IPA_DMA;
+	ipa_ep_cfg.mode.dst = IPA_CLIENT_TEST3_CONS;
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_DEAGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_MBIM_16;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[1]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[1]->ep,
+				  IPA_CLIENT_TEST_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[1]->mem,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* configure deaggregation on Rx */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.mode.mode = IPA_DMA;
+	ipa_ep_cfg.mode.dst = IPA_CLIENT_TEST_CONS;
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_DEAGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_MBIM_16;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST2_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[2]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[2]->ep,
+				  IPA_CLIENT_TEST2_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[2]->mem,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Prepare EP configuration details */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.mode.mode = IPA_DMA;
+	ipa_ep_cfg.mode.dst = IPA_CLIENT_TEST2_CONS;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST4_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[3]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[3]->ep,
+				  IPA_CLIENT_TEST4_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[3]->mem,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+fail:
+	/* cleanup and tear down goes here */
+	return res;
+}
+
+/*
+ Configures the system as follows:
+ This configuration is for 1 input pipe and 1 output pipe:
+ /dev/to_ipa_0 -> MEM -> GSI -> IPA -> GSI -> MEM -> /dev/from_ipa_0
+ /dev/to_ipa_1 -> MEM -> GSI -> IPA -> GSI -> MEM -> /dev/from_ipa_1
+ from_ipa_0, from_ipa_1 transfer IPA_MBIM_AGGR aggregated packets
+ to_ipa_0, to_ipa_1 transfer raw packets
+*/
+int configure_system_10(void)
+{
+	int res = 0;
+	struct ipa_ep_cfg ipa_ep_cfg;
+	enum ipa_aggr_mode mode;
+	struct ipa_sys_connect_params sys_in;
+	unsigned long ipa_gsi_hdl;
+	u32 ipa_pipe_num;
+
+	mode = IPA_MBIM_AGGR;
+	res = ipa_set_aggr_mode(mode);
+	if (res)
+		goto fail;
+	res = ipa_set_single_ndp_per_mbim(false);
+	if (res)
+		goto fail;
+
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	IPATEST_DBG("Configure_system_10 was called\n");
+
+	/* Setup GSI pipes */
+	to_ipa_devs[0]->dma_ep.src_pipe_index = 4;
+	to_ipa_devs[0]->dma_ep.dest_pipe_index = 5;
+
+	from_ipa_devs[0]->dma_ep.src_pipe_index = 6;
+	from_ipa_devs[0]->dma_ep.dest_pipe_index = 7;
+
+	/* configure aggregation on Tx */
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_MBIM_16;
+	ipa_ep_cfg.aggr.aggr_byte_limit = 0;
+	ipa_ep_cfg.aggr.aggr_time_limit = 0;
+	ipa_ep_cfg.hdr.hdr_len = 1;
+
+	/* Connect IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Prepare EP configuration details */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.mode.mode = IPA_DMA;
+	ipa_ep_cfg.mode.dst = IPA_CLIENT_TEST_CONS;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl,
+			&ipa_pipe_num, &to_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[0]->mem,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+fail:
+	/* cleanup and tear down goes here */
+	return res;
+}
+
+int configure_system_12(void)
+{
+	int res = 0;
+	struct ipa_ep_cfg ipa_ep_cfg;
+	enum ipa_aggr_mode mode;
+	char qcncm_sig[3];
+
+	struct ipa_sys_connect_params sys_in;
+	unsigned long ipa_gsi_hdl;
+	u32 ipa_pipe_num;
+	mode = IPA_QCNCM_AGGR;
+	res = ipa_set_aggr_mode(mode);
+	if (res)
+		goto fail;
+	res = ipa_set_single_ndp_per_mbim(false);
+	if (res)
+		goto fail;
+	qcncm_sig[0] = 0x51;
+	qcncm_sig[1] = 0x4e;
+	qcncm_sig[2] = 0x44;
+	res = ipa_set_qcncm_ndp_sig(qcncm_sig);
+	if (res)
+		goto fail;
+
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+
+
+	/* Connect IPA -> first Rx GSI */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_MBIM_16;
+	ipa_ep_cfg.aggr.aggr_byte_limit = 1;
+	ipa_ep_cfg.aggr.aggr_time_limit = 0;
+	ipa_ep_cfg.hdr.hdr_len = 1;
+
+	/* Connect first Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST2_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl,
+			&ipa_pipe_num, &from_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST2_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+
+		/* Connect second Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST3_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl,
+			&ipa_pipe_num, &from_ipa_devs[1]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[1]->ep,
+				  IPA_CLIENT_TEST3_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Connect IPA -> first Rx GSI */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_MBIM_16;
+	ipa_ep_cfg.aggr.aggr_byte_limit = 0;
+	ipa_ep_cfg.aggr.aggr_time_limit = 30;
+	if (ipa_get_hw_type() >= IPA_HW_v4_2)
+		ipa_ep_cfg.aggr.aggr_time_limit *= 1000;
+	ipa_ep_cfg.hdr.hdr_len = 1;
+
+	/* Connect first Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl,
+			&ipa_pipe_num, &from_ipa_devs[2]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[2]->ep,
+				  IPA_CLIENT_TEST_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Connect IPA -> first Rx GSI */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_MBIM_16;
+	ipa_ep_cfg.aggr.aggr_byte_limit = 0;
+	ipa_ep_cfg.aggr.aggr_time_limit = 0;
+	ipa_ep_cfg.hdr.hdr_len = 1;
+
+	/* Connect first Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST4_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl,
+			&ipa_pipe_num, &from_ipa_devs[3]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[3]->ep,
+				  IPA_CLIENT_TEST4_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Connect Tx GSI -> IPA */
+	/* Prepare an endpoint configuration structure */
+	res = configure_ipa_endpoint(&ipa_ep_cfg, IPA_BASIC);
+	if (res)
+		goto fail;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl,
+			&ipa_pipe_num, &to_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[0]->mem,
+				  ipa_gsi_hdl);
+
+	if (res)
+		goto fail;
+
+	/* Connect Tx GSI -> IPA */
+	/* Prepare an endpoint configuration structure */
+	res = configure_ipa_endpoint(&ipa_ep_cfg, IPA_BASIC);
+	if (res)
+		goto fail;
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_DEAGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_MBIM_16;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST2_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl,
+			&ipa_pipe_num, &to_ipa_devs[1]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[1]->ep,
+				  IPA_CLIENT_TEST2_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[1]->mem,
+				  ipa_gsi_hdl);
+
+	if (res)
+		goto fail;
+
+fail:
+	/* cleanup and tear down goes here */
+	return res;
+}
+
+void suspend_handler(enum ipa_irq_type interrupt,
+				void *private_data,
+				void *interrupt_data)
+{
+	u32 *suspend_data;
+	u32 clnt_hdl;
+	u32 gsi_chan_hdl;
+	struct ipa_ep_cfg_ctrl ipa_to_usb_ep_cfg_ctrl;
+	int i, res;
+
+	suspend_data =
+		((struct ipa_tx_suspend_irq_data *)interrupt_data)->endpoints;
+	clnt_hdl =
+		((struct ipa_tx_suspend_private_data *)private_data)->clnt_hdl;
+	gsi_chan_hdl =
+		((struct ipa_tx_suspend_private_data *)private_data)->gsi_chan_hdl;
+
+	IPATEST_DBG("in suspend handler: interrupt=%d, private_data=%d, interrupt_data=",
+			 interrupt, clnt_hdl, suspend_data[0], suspend_data[1]);
+	for (i = 0; i < IPA_EP_ARR_SIZE; i++)
+		IPATEST_DBG("%d", suspend_data[i]);
+
+	IPATEST_DBG("\nEnabling back data path for IPA_CLIENT_USB_CONS\n");
+	memset(&ipa_to_usb_ep_cfg_ctrl, 0 , sizeof(struct ipa_ep_cfg_ctrl));
+	ipa_to_usb_ep_cfg_ctrl.ipa_ep_suspend = false;
+
+	if(ipa_get_hw_type() >= IPA_HW_v4_0)
+		res = gsi_start_channel(gsi_chan_hdl);
+	else
+		res = ipa_cfg_ep_ctrl(clnt_hdl, &ipa_to_usb_ep_cfg_ctrl);
+
+	if (res)
+		IPATEST_ERR("failed enabling back data path for IPA_CLIENT_USB_CONS\n");
+}
+/*
+ * Configures the system as follows:
+ * This configuration is for one input pipe and one output pipe
+ * where both are USB1
+ * /dev/to_ipa_0 -> MEM -> GSI -> IPA -> GSI-> MEM -> /dev/from_ipa_0
+ * Those clients will be configured in DMA mode thus no Header removal/insertion
+ * will be made on their data.
+ * Then disable USB_CONS EP for creating the suspend interrupt and register
+ * a handler for it.
+*/
+int configure_system_19(void)
+{
+	struct ipa_ep_cfg_ctrl ipa_to_usb_ep_cfg_ctrl;
+	int res;
+
+	res = configure_system_1();
+	if (res) {
+		IPATEST_ERR("configure system (19) failed\n");
+		goto fail;
+	}
+
+	memset(&ipa_to_usb_ep_cfg_ctrl, 0 , sizeof(struct ipa_ep_cfg_ctrl));
+	ipa_to_usb_ep_cfg_ctrl.ipa_ep_suspend = true;
+
+	if(ipa_get_hw_type() >= IPA_HW_v4_0)
+		res = ipa_stop_gsi_channel(from_ipa_devs[0]->ipa_client_hdl);
+	else
+		res = ipa_cfg_ep_ctrl(from_ipa_devs[0]->ipa_client_hdl, &ipa_to_usb_ep_cfg_ctrl);
+
+	if (res) {
+		IPATEST_ERR("end-point ctrl register configuration failed\n");
+		goto fail;
+	}
+	IPATEST_DBG("end-point ctrl register configured successfully (ipa_ep_suspend = true)\n");
+
+	return 0;
+
+fail:
+
+	return res;
+}
+
+int configure_system_18(void)
+{
+	int res = 0;
+	struct ipa_ep_cfg ipa_ep_cfg;
+	struct ipa_sys_connect_params sys_in;
+	unsigned long ipa_gsi_hdl;
+	u32 ipa_pipe_num;
+
+	datapath_ds_clean();
+
+	/* Connect IPA -> Rx GSI */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+
+	/* Connect Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	sys_in.notify = notify_ipa_write_done;
+	if (ipa3_sys_setup(&sys_in,
+				&ipa_gsi_hdl,
+				&ipa_pipe_num,
+				&from_ipa_devs[0]->ipa_client_hdl,
+				false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+
+	/* Connect Tx GSI -> IPA */
+	/* Prepare an endpoint configuration structure */
+	res = configure_ipa_endpoint(&ipa_ep_cfg, IPA_BASIC);
+	if (res)
+		goto fail;
+
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	sys_in.notify = notify_ipa_received;
+	if (ipa3_sys_setup(&sys_in,
+			&ipa_gsi_hdl,
+			&ipa_pipe_num,
+			&to_ipa_devs[0]->ipa_client_hdl,
+			false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[0]->mem,
+				  ipa_gsi_hdl);
+
+	if (res)
+		goto fail;
+
+fail:
+	/* cleanup and tear down goes here */
+	return res;
+}
+
+
+/**
+ * Read File.
+ *
+ * @note This function is used by User Mode Application
+ * in order to read data from the device node /dev/ipa_exception_pipe.
+ * This implementation assumes Single Reader and Single Writer.
+ *
+ */
+ssize_t exception_kfifo_read(struct file *filp, char __user *buf,
+		       size_t count, loff_t *p_pos)
+{
+	int ret = 0;
+	size_t data_len = 0;
+	unsigned int copied;
+
+	if (kfifo_is_empty(
+			&(p_exception_hdl_data->
+					notify_cb_data.exception_kfifo))) {
+		/* Optimization*/
+
+		IPATEST_DBG("No Data in exception pipe, Sleeping...\n");
+		msleep(200);
+		IPATEST_DBG("Sleeping Done...\n");
+		if (kfifo_is_empty(&(p_exception_hdl_data->
+				notify_cb_data.exception_kfifo))) {
+			IPATEST_DBG("No Data in exception pipe.Returning\n");
+			return 0;
+		}
+	}
+	data_len = kfifo_peek_len
+			(&(p_exception_hdl_data
+					->notify_cb_data.exception_kfifo));
+	if (data_len > count) {
+		IPATEST_ERR("buffer(%zu) too small (%zu) required\n",
+			data_len, count);
+		return -ENOSPC;
+	}
+	ret = kfifo_to_user(&
+			(p_exception_hdl_data->
+					notify_cb_data.exception_kfifo)
+			, buf, data_len, &copied);
+#if (EXCEPTION_KFIFO_DEBUG_VERBOSE)
+	{
+		int i = 0;
+
+		IPATEST_DBG("Exception packet's length=%zu, Packet's content:\n"
+					, data_len);
+		if (data_len - 3 > 0) {
+			for (i = 0; i < data_len-4; i += 4) {
+				IPATEST_DUMP("%02x %02x %02x %02x\n",
+						(buf)[i], (buf)[i+1],
+						(buf)[i+2], (buf)[i+3]);
+			}
+		}
+	}
+#endif
+	return ret ? ret : copied;
+}
+
+/**
+ * Write File.
+ *
+ * @note This function is used by User
+ * in order to write data to the device node /dev/ipa_exception_pipe.
+ * This implementation assumes Single Reader and Single Writer.
+ *
+ */
+ssize_t exception_kfifo_write(struct file *file, const char __user *buf,
+	size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned int copied;
+
+	ret = kfifo_from_user
+			(&(p_exception_hdl_data->notify_cb_data.exception_kfifo)
+					, buf, count, &copied);
+	if (ret) {
+		IPATEST_ERR("(%d/%zu) Bytes were written to kfifo.\n",
+			copied, count);
+	}
+	return ret ? ret : copied;
+}
+
+static const struct file_operations exception_fops = {
+	.owner = THIS_MODULE,
+	.read = exception_kfifo_read,
+	.write = exception_kfifo_write,
+};
+
+void notify_upon_exception(void *priv,
+		enum ipa_dp_evt_type evt, unsigned long data)
+{
+	int i = 0;
+	size_t data_len;
+	int res = 0;
+	char *p_data = NULL;
+	struct sk_buff *p_sk_buff = (struct sk_buff *)data;
+	struct notify_cb_data_st *p_notify_cb_data
+		= (struct notify_cb_data_st *)priv;
+
+	IPATEST_DBG("was called, evt=%s(%d)",
+			(evt == IPA_RECEIVE) ?
+				"IPA_RECEIVE" :
+				"IPA_WRITE_DONE", evt);
+	if (IPA_RECEIVE != evt) {
+		IPATEST_ERR("unexpected value of evt == %d\n", evt);
+		return;
+	}
+
+#if (SAVE_HEADER)
+	data_len = p_sk_buff->len + 8; /* store len */
+	p_data = (p_sk_buff->data) - 8; /* store pointer to the data */
+#else
+	data_len = p_sk_buff->len; /* store len */
+	p_data = p_sk_buff->data; /* store pointer to the data */
+#endif
+
+#if (EXCEPTION_KFIFO_DEBUG_VERBOSE)
+		IPATEST_DBG("Exception packet length = %zu,Packet content:\n",
+				data_len);
+		for (i = 0; i < data_len - 4; i += 4) {
+			IPATEST_DUMP("%02x %02x %02x %02x",
+					(p_data)[i], (p_data)[i+1],
+					(p_data)[i+2], (p_data)[i+3]);
+		}
+#endif
+	res = kfifo_in(
+			&p_notify_cb_data->exception_kfifo,
+			p_data , data_len);
+	if (res != data_len) {
+		IPATEST_ERR("kfifo_in copied %d Bytes instead of %zu\n",
+				res, data_len);
+		return;
+	}
+}
+/*
+ * This function Inits the KFIFO and the Device Node of the exceptions
+ */
+int exception_hdl_init(void)
+{
+	int res = 0;
+	struct notify_cb_data_st *p_notify_cb_data;
+
+	IPATEST_DBG("called.\n");
+
+	if (NULL != p_exception_hdl_data) {
+		IPATEST_ERR("p_exception_hdl_data is initialized?=(0x%px)\n",
+			p_exception_hdl_data);
+		return -EINVAL;
+	}
+	p_exception_hdl_data =
+			kzalloc(sizeof(struct exception_hdl_data), GFP_KERNEL);
+	if (NULL == p_exception_hdl_data) {
+		IPATEST_ERR("kzalloc return NULL, can't alloc %zu Bytes\n",
+			sizeof(struct exception_hdl_data));
+		return -ENOMEM;
+	}
+	IPATEST_DBG("Continue...\n");
+	p_notify_cb_data = &(p_exception_hdl_data->notify_cb_data);
+
+	res = kfifo_alloc(&(p_notify_cb_data->exception_kfifo)
+			, EXCEPTION_KFIFO_SIZE*(sizeof(char)*RX_DESCRIPTOR_SIZE)
+			, GFP_KERNEL);
+	if (0 != res) {
+		IPATEST_ERR("kfifo_alloc returned error (%d)\n",
+			res);
+		return res;
+	}
+	res = alloc_chrdev_region(&p_exception_hdl_data->dev_num
+			, 0, 1, EXCEPTION_DRV_NAME);
+	if (0 != res) {
+		IPATEST_ERR("alloc_chrdev_region failed (%d)\n", res);
+		return res;
+	}
+	p_exception_hdl_data->class =
+			class_create(THIS_MODULE, EXCEPTION_DRV_NAME);
+	p_exception_hdl_data->dev =
+			device_create(p_exception_hdl_data->class
+					, NULL, p_exception_hdl_data->dev_num,
+				      ipa_test, EXCEPTION_DRV_NAME);
+	if (IS_ERR(p_exception_hdl_data->dev)) {
+		IPATEST_ERR("device_create returned error\n");
+		return -ENODEV;
+	}
+	p_exception_hdl_data->p_cdev = cdev_alloc();
+	if (NULL == p_exception_hdl_data->p_cdev) {
+		IPATEST_ERR("cdev_alloc() returned NULL (0x%px)\n"
+				, p_exception_hdl_data->p_cdev);
+		return -EINVAL;
+	}
+	cdev_init(p_exception_hdl_data->p_cdev, &exception_fops);
+	p_exception_hdl_data->p_cdev->owner = THIS_MODULE;
+	res = cdev_add(p_exception_hdl_data->p_cdev
+			, p_exception_hdl_data->dev_num, 1);
+	if (0 != res) {
+		IPATEST_ERR("cdev_add failed (%d)\n", res);
+		return res;
+	}
+
+	IPATEST_DBG("completed.(%d)\n", res);
+	return res;
+}
+/*
+ * Clear the Exception Device and KFIFO
+ */
+void exception_hdl_exit(void)
+{
+
+	unregister_chrdev_region
+			(p_exception_hdl_data->dev_num, 1);
+	kfifo_free(&(p_exception_hdl_data
+				->notify_cb_data.exception_kfifo));
+	/* freeing kfifo */
+	memset(&(p_exception_hdl_data
+				->notify_cb_data.exception_kfifo), 0,
+			sizeof(p_exception_hdl_data
+				->notify_cb_data.exception_kfifo));
+	kfree(p_exception_hdl_data);
+	p_exception_hdl_data = NULL;
+}
+
+/* Configuration used for Exception Tests */
+int configure_system_7(void)
+{
+	int res = 0;
+	struct ipa_ep_cfg ipa_ep_cfg;
+
+	struct ipa_sys_connect_params sys_in;
+	unsigned long ipa_gsi_hdl;
+	u32 ipa_pipe_num;
+
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+
+	res = exception_hdl_init();
+	if (0 != res) {
+		IPATEST_ERR("exception_hdl_init() failed (%d)\n", res);
+		return res;
+	}
+
+
+	/* Connect first Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST2_CONS;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[0]->ipa_client_hdl,
+			false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST2_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Connect second Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST3_CONS;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[1]->ipa_client_hdl,
+			false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[1]->ep,
+				  IPA_CLIENT_TEST3_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Connect third (Default) Rx IPA --> APPS MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST4_CONS;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[2]->ipa_client_hdl,
+			false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[2]->ep,
+				  IPA_CLIENT_TEST4_CONS,
+				  ipa_pipe_num,
+				  ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+
+	/* Connect Tx GSI -> IPA */
+	/* Prepare an endpoint configuration structure */
+	res = configure_ipa_endpoint(&ipa_ep_cfg, IPA_BASIC);
+	if (res)
+		goto fail;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	sys_in.notify = &notify_upon_exception;
+	sys_in.priv = &(p_exception_hdl_data->notify_cb_data);
+
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[0]->ipa_client_hdl,
+			false))
+		goto fail;
+
+	/* Connect APPS MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[0]->mem,
+				  ipa_gsi_hdl);
+
+	if (res)
+		goto fail;
+fail:
+	/* cleanup and tear down goes here */
+	return res;
+}
+
+void destroy_channel_device(struct channel_dev *channel_dev)
+{
+	int res = 0;
+
+	IPATEST_DBG("Destroying device channel_dev = 0x%px,name %s.\n",
+	       channel_dev, channel_dev->name);
+
+	IPATEST_DBG("ep=0x%px gsi_chan_hdl=0x%lx\n", &channel_dev->ep, channel_dev->ep.gsi_chan_hdl);
+	if (channel_dev->ep.gsi_valid) {
+		IPATEST_DBG("stopping channel 0x%lx\n", channel_dev->ep.gsi_chan_hdl);
+		res = ipa_stop_gsi_channel(channel_dev->ipa_client_hdl);
+		if (res != GSI_STATUS_SUCCESS)
+			IPATEST_ERR("ipa_stop_gsi_channel failed %d\n\n", res);
+
+		IPATEST_DBG("reset channel 0x%lx\n", channel_dev->ep.gsi_chan_hdl);
+		res = gsi_reset_channel(channel_dev->ep.gsi_chan_hdl);
+		if (res != GSI_STATUS_SUCCESS)
+			IPATEST_ERR("gsi_reset_channel failed %d\n\n", res);
+
+		IPATEST_DBG("deallocate channel 0x%lx\n", channel_dev->ep.gsi_chan_hdl);
+		res = gsi_dealloc_channel(channel_dev->ep.gsi_chan_hdl);
+		if (res != GSI_STATUS_SUCCESS)
+			IPATEST_ERR("gsi_dealloc_channel failed %d\n\n", res);
+
+		dma_free_coherent(ipa3_get_pdev(), channel_dev->ep.gsi_channel_props.ring_len, channel_dev->ep.gsi_channel_props.ring_base_vaddr, channel_dev->ep.gsi_channel_props.ring_base_addr);
+
+		IPATEST_DBG("deallocate channel event ring 0x%lx\n", channel_dev->ep.gsi_evt_ring_hdl);
+		res = gsi_dealloc_evt_ring(channel_dev->ep.gsi_evt_ring_hdl);
+		if (res != GSI_STATUS_SUCCESS)
+			IPATEST_ERR("gsi_dealloc_evt_ring failed %d\n\n", res);
+		dma_free_coherent(ipa3_get_pdev(), channel_dev->ep.gsi_evt_ring_props.ring_len, channel_dev->ep.gsi_evt_ring_props.ring_base_vaddr, channel_dev->ep.gsi_evt_ring_props.ring_base_addr);
+
+		res = ipa3_sys_teardown(channel_dev->ipa_client_hdl);
+		if (res) {
+			IPATEST_ERR("Failure on ipa_sys_teardown(),"
+				" channel_dev = 0x%px, res = %d.\n",
+				channel_dev, res);
+		}
+	}
+
+
+	cdev_del(&channel_dev->cdev);
+	memset(&channel_dev->cdev, 0, sizeof(channel_dev->cdev));
+	device_destroy(channel_dev->class, channel_dev->dev_num);
+	unregister_chrdev_region(channel_dev->dev_num, 1);
+	class_destroy(channel_dev->class);
+	test_free_mem(&channel_dev->mem);
+	memset(channel_dev, 0, sizeof(struct channel_dev));
+	kfree(channel_dev);
+}
+
+void destroy_channel_devices(void)
+{
+	IPATEST_DBG("-----Tear Down----\n");
+	while (ipa_test->num_tx_channels > 0) {
+		IPATEST_DBG("-- num_tx_channels = %d --\n",
+			ipa_test->num_tx_channels);
+
+		destroy_channel_device(
+			ipa_test->tx_channels[--ipa_test->num_tx_channels]);
+		ipa_test->tx_channels[ipa_test->num_tx_channels] = NULL;
+	}
+
+	while (ipa_test->num_rx_channels > 0) {
+		IPATEST_DBG("-- num_rx_channels = %d --\n",
+			ipa_test->num_rx_channels);
+		destroy_channel_device
+			(from_ipa_devs[--ipa_test->num_rx_channels]);
+		from_ipa_devs[ipa_test->num_rx_channels] = NULL;
+	}
+}
+
+int register_lan_interface(void)
+{
+	struct ipa_rx_intf rx_intf;
+	struct ipa_tx_intf tx_intf;
+	struct ipa_ioc_tx_intf_prop tx_prop;
+	struct ipa_ioc_rx_intf_prop rx_prop;
+	char *name = "rmnet1";
+	int res;
+
+	IPATEST_DBG(":new version\n");
+	memset(&tx_prop, 0, sizeof(tx_prop));
+	tx_prop.ip = IPA_IP_v6;
+	tx_prop.dst_pipe = IPA_CLIENT_TEST_CONS;
+
+	memset(&rx_prop, 0, sizeof(rx_prop));
+	rx_prop.ip = IPA_IP_v6;
+	rx_prop.src_pipe = IPA_CLIENT_TEST_PROD;
+
+	memset(&rx_intf, 0, sizeof(rx_intf));
+	rx_intf.num_props = 1;
+	rx_intf.prop = &rx_prop;
+
+	memset(&tx_intf, 0, sizeof(tx_intf));
+	tx_intf.num_props = 1;
+	tx_intf.prop = &tx_prop;
+
+	res = ipa_register_intf(name, &tx_intf, &rx_intf);
+	if (res != 0)
+		goto fail;
+
+	IPATEST_DBG(":registered interface %s !\n", name);
+
+fail:
+	return res;
+}
+
+/* add wlan header to ipa */
+
+#define IPA_TO_WLAN_HEADER_NAME "wlan0"
+int add_wlan_header(void)
+{
+
+#define IPA_TO_WLAN_HEADER_LEN  34
+
+	uint8_t hdr[IPA_TO_WLAN_HEADER_LEN + 1] = {
+		/* HTC Header - 6 bytes */
+		0x00, 0x00,  /* Reserved */
+		0x00, 0x00, /* length to be filled by IPA,
+					after adding 32 with IP Payload
+					length 32 will be
+					programmed while
+					intializing the header */
+		0x00, 0x00,  /* Reserved */
+		/* WMI header - 6 bytes*/
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+		/* 802.3 header - 14 bytes*/
+		0x00, 0x03, 0x7f, 0x44, 0x33, 0x89,
+		/* Des. MAC to be filled by IPA */
+		0x00, 0x03, 0x7f, 0x17, 0x12, 0x69,
+		/* Src. MAC to be filled by IPA */
+		0x00, 0x00,
+		/* length can be zero */
+
+		/* LLC SNAP header - 8 bytes */
+		0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00,
+		0x08, 0x00  /* type value(2 bytes) to
+						be filled by IPA, by reading
+						from ethernet header */
+		/* 0x0800 - IPV4, 0x86dd - IPV6 */
+	};
+
+	int ret = 0;
+	int len = 0;
+	struct ipa_ioc_add_hdr *ipa_to_wlan_header_partial;
+	struct ipa_hdr_add ipa_to_wlan_header;
+
+	memset(&ipa_to_wlan_header, 0, sizeof(ipa_to_wlan_header));
+	/* Copy header name */
+	memcpy(ipa_to_wlan_header.name,
+				 IPA_TO_WLAN_HEADER_NAME,
+				 sizeof(IPA_TO_WLAN_HEADER_NAME));
+
+	/* poplate other fields of header add */
+	ipa_to_wlan_header.hdr_len = IPA_TO_WLAN_HEADER_LEN;
+	ipa_to_wlan_header.is_partial = 1;
+	ipa_to_wlan_header.hdr_hdl = 0;
+	ipa_to_wlan_header.status = -1;
+	/* copy the parital header */
+	memcpy(ipa_to_wlan_header.hdr, hdr, IPA_TO_WLAN_HEADER_LEN);
+
+	/* Add wlan partial header to ipa */
+	len = (sizeof(struct ipa_ioc_add_hdr)) +
+			(1 * sizeof(struct ipa_hdr_add));
+	ipa_to_wlan_header_partial = kmalloc(len, GFP_KERNEL);
+	if (!ipa_to_wlan_header_partial) {
+		IPATEST_ERR("Memory allocation failure");
+		return false;
+	}
+
+	ipa_to_wlan_header_partial->commit = 1;
+	ipa_to_wlan_header_partial->num_hdrs = 1;
+	memcpy(&ipa_to_wlan_header_partial->hdr[0],
+		       &ipa_to_wlan_header,
+		       sizeof(ipa_to_wlan_header));
+	ret = ipa_add_hdr(ipa_to_wlan_header_partial);
+	if (ret) {
+		IPATEST_ERR("unable to add wlan header %d", ret);
+		goto fail;
+	} else if (ipa_to_wlan_header_partial->hdr[0].status) {
+		IPATEST_ERR("unable to add wlan header %d", ret);
+		goto fail;
+	}
+
+	IPATEST_DBG("added wlan header successfully\n");
+
+fail:
+	kfree(ipa_to_wlan_header_partial);
+
+	return ret;
+}
+
+/* Wlan interface has 4 rx and 1 Tx endpoint */
+int register_wlan_interface(void)
+{
+	struct ipa_rx_intf rx_intf;
+	struct ipa_tx_intf tx_intf;
+	struct ipa_ioc_tx_intf_prop tx_prop[4];
+	struct ipa_ioc_rx_intf_prop rx_prop;
+	char *name = "eth0";
+	int res, index = 0;
+
+	res = add_wlan_header();
+	if (res)
+		return res;
+
+	memset(&tx_prop, 0, 4 * sizeof(struct ipa_ioc_tx_intf_prop));
+
+	index = 0;
+	tx_prop[index].ip = IPA_IP_v6;
+	tx_prop[index].dst_pipe = IPA_CLIENT_TEST1_CONS;
+	memcpy(tx_prop[index].hdr_name, IPA_TO_WLAN_HEADER_NAME,
+		  sizeof(IPA_TO_WLAN_HEADER_NAME));
+
+	index++;
+	tx_prop[index].ip = IPA_IP_v6;
+	tx_prop[index].dst_pipe = IPA_CLIENT_TEST2_CONS;
+	memcpy(tx_prop[index].hdr_name, IPA_TO_WLAN_HEADER_NAME,
+			sizeof(IPA_TO_WLAN_HEADER_NAME));
+
+	index++;
+	tx_prop[index].ip = IPA_IP_v6;
+	tx_prop[index].dst_pipe = IPA_CLIENT_TEST3_CONS;
+	memcpy(tx_prop[index].hdr_name, IPA_TO_WLAN_HEADER_NAME,
+			sizeof(IPA_TO_WLAN_HEADER_NAME));
+
+	index++;
+	tx_prop[index].ip = IPA_IP_v6;
+	tx_prop[index].dst_pipe = IPA_CLIENT_TEST4_CONS;
+	memcpy(tx_prop[index].hdr_name, IPA_TO_WLAN_HEADER_NAME,
+			sizeof(IPA_TO_WLAN_HEADER_NAME));
+
+	memset(&rx_prop, 0, sizeof(struct ipa_ioc_rx_intf_prop));
+	rx_prop.ip = IPA_IP_v6;
+	rx_prop.src_pipe = IPA_CLIENT_TEST1_PROD;
+
+	memset(&rx_intf, 0, sizeof(rx_intf));
+	rx_intf.num_props = 1;
+	rx_intf.prop = &rx_prop;
+
+	memset(&tx_intf, 0, sizeof(tx_intf));
+	tx_intf.num_props = 4;
+	tx_intf.prop = tx_prop;
+
+	res = ipa_register_intf(name, &tx_intf, &rx_intf);
+	if (res) {
+		IPATEST_ERR("Unable to register interface %s, %d\n",
+				name, res);
+		return res;
+	}
+
+	IPATEST_DBG("Registered interface %s\n", name);
+	return res;
+}
+
+/* Wan interface has 1 rx and 1 Tx endpoint */
+int register_wan_interface(void)
+{
+	struct ipa_rx_intf rx_intf;
+	struct ipa_tx_intf tx_intf;
+	struct ipa_ioc_tx_intf_prop tx_prop;
+	struct ipa_ioc_rx_intf_prop rx_prop;
+	char *name = "rmnet0";
+	int res;
+
+	memset(&tx_prop, 0, sizeof(tx_prop));
+	tx_prop.ip = IPA_IP_v6;
+	tx_prop.dst_pipe = IPA_CLIENT_TEST3_CONS;
+
+	memset(&rx_prop, 0, sizeof(rx_prop));
+	rx_prop.ip = IPA_IP_v6;
+	rx_prop.src_pipe = IPA_CLIENT_TEST3_PROD;
+
+	memset(&rx_intf, 0, sizeof(rx_intf));
+	rx_intf.num_props = 1;
+	rx_intf.prop = &rx_prop;
+
+	memset(&tx_intf, 0, sizeof(tx_intf));
+	tx_intf.num_props = 1;
+	tx_intf.prop = &tx_prop;
+
+	res = ipa_register_intf(name, &tx_intf, &rx_intf);
+	if (res != 0)
+		goto fail;
+
+	IPATEST_DBG("registered interface %s !\n", name);
+
+fail:
+	return res;
+}
+
+/*
+ Configures the system with one input to IPA and 2 outputs.
+ /dev/to_ipa_0 -> MEM -> GSI -> IPA |-> GSI
+ -> MEM -> /dev/from_ipa_0
+|-> GSI -> MEM -> /dev/from_ipa_1
+*/
+int configure_system_20(void)
+{
+	int res = 0;
+	int index = 0;
+	struct ipa_ep_cfg ipa_ep_cfg;
+
+	struct ipa_sys_connect_params sys_in;
+	unsigned long ipa_gsi_hdl;
+	u32 ipa_pipe_num;
+
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+
+
+	/* Connect first Rx IPA --> AP MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST2_CONS;
+	if (ipa3_sys_setup(&sys_in,
+		&ipa_gsi_hdl, &ipa_pipe_num,
+		&from_ipa_devs[index]->ipa_client_hdl, false))
+		goto fail;
+
+	res = connect_ipa_to_apps(&from_ipa_devs[index]->ep,
+		IPA_CLIENT_TEST2_CONS,
+		ipa_pipe_num,
+		ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+
+	index++;
+
+	/* Connect IPA -> 1 Tx GSI */
+	/* RNDIS Aggregation with ETH2 header */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_GENERIC;
+	ipa_ep_cfg.aggr.aggr_byte_limit = 1;
+	ipa_ep_cfg.aggr.aggr_time_limit = 0;
+	ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = true;
+	ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 12;
+	ipa_ep_cfg.hdr.hdr_additional_const_len = 14;
+	ipa_ep_cfg.hdr.hdr_len = 58;
+	ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
+	ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_valid = true;
+	ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad = IPA_HDR_TOTAL_LEN;
+	ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_offset = 4;
+
+	/* Connect 1 Tx IPA --> AP MEM */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST3_CONS;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(
+		&sys_in,
+		&ipa_gsi_hdl,
+		&ipa_pipe_num,
+		&from_ipa_devs[index]->ipa_client_hdl,
+		false))
+		goto fail;
+
+	res = connect_ipa_to_apps(
+		&from_ipa_devs[index]->ep,
+		IPA_CLIENT_TEST3_CONS,
+		ipa_pipe_num,
+		ipa_gsi_hdl);
+	if (res)
+		goto fail;
+
+	/* Connect Rx GSI -> IPA */
+	/* Prepare an endpoint configuration structure */
+	res = configure_ipa_endpoint(&ipa_ep_cfg, IPA_BASIC);
+	if (res)
+		goto fail;
+
+	/* configure RNDIS+ETH2 header removal on Rx */
+	/* configure RNDIS de-aggregation on Rx */
+	ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_DEAGGR;
+	ipa_ep_cfg.aggr.aggr = IPA_GENERIC;
+	ipa_ep_cfg.deaggr.deaggr_hdr_len = 44; /* RNDIS hdr */
+	ipa_ep_cfg.deaggr.packet_offset_valid = true;
+	ipa_ep_cfg.deaggr.packet_offset_location = 8;
+	ipa_ep_cfg.hdr.hdr_len = 14; /* Ethernet header */
+	ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 12;
+	ipa_ep_cfg.hdr.hdr_remove_additional = false;
+	ipa_ep_cfg.hdr_ext.hdr_little_endian = 1;
+	ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_valid = 1;
+	ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad = IPA_HDR_TOTAL_LEN;
+	ipa_ep_cfg.hdr_ext.hdr_payload_len_inc_padding = 0;
+	ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_offset = 4;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[0]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect AP MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[0]->ep,
+				  IPA_CLIENT_TEST_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[0]->mem,
+				  ipa_gsi_hdl);
+
+
+	if (res)
+		goto fail;
+
+	/* Connect Tx GSI -> IPA */
+	/* Prepare an endpoint configuration structure */
+	res = configure_ipa_endpoint(&ipa_ep_cfg, IPA_BASIC);
+	if (res)
+		goto fail;
+
+	/* configure ETH2+WLAN\ETH2_802_1Q (18B) header removal on Tx */
+	ipa_ep_cfg.hdr.hdr_len = ETH_HLEN + IPA_TEST_ADDITIONAL_HDR_LEN;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST2_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[1]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect AP MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[1]->ep,
+				  IPA_CLIENT_TEST2_PROD,
+				  ipa_pipe_num,
+				  &to_ipa_devs[1]->mem,
+				  ipa_gsi_hdl);
+
+
+	if (res)
+		goto fail;
+
+	/* Connect Tx GSI -> IPA */
+	/* Prepare an endpoint configuration structure */
+	res = configure_ipa_endpoint(&ipa_ep_cfg, IPA_BASIC);
+	if (res)
+		goto fail;
+
+	/* configure ETH2 header removal on Tx */
+	ipa_ep_cfg.hdr.hdr_len = ETH_HLEN;
+
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = IPA_CLIENT_TEST3_PROD;
+	sys_in.ipa_ep_cfg = ipa_ep_cfg;
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+		&to_ipa_devs[2]->ipa_client_hdl, false))
+		goto fail;
+
+	/* Connect AP MEM --> Tx IPA */
+	res = connect_apps_to_ipa(&to_ipa_devs[2]->ep,
+		IPA_CLIENT_TEST3_PROD,
+		ipa_pipe_num,
+		&to_ipa_devs[2]->mem,
+		ipa_gsi_hdl);
+
+
+	if (res)
+		goto fail;
+
+fail:
+	/* cleanup and tear down goes here */
+	return res;
+}
+
+static char **str_split(char *str, const char *delim)
+{
+	char **res = NULL;
+	char **tmp = NULL;
+	char *p = strsep(&str, delim);
+	int n_spaces = 0;
+
+	/* split string and append tokens to 'res' */
+	while (p) {
+		tmp = krealloc(res, sizeof(char *) * ++n_spaces, GFP_KERNEL);
+
+		if (tmp == NULL) {
+			IPATEST_ERR("krealloc failed\n");
+			goto fail; /* memory allocation failed */
+		}
+
+		res = tmp;
+		res[n_spaces-1] = p;
+		p = strsep(&str, delim);
+	}
+	/* realloc one extra element for the last NULL */
+	tmp = krealloc(res, sizeof(char *) * (n_spaces+1), GFP_KERNEL);
+	if (tmp == NULL) {
+		IPATEST_ERR("krealloc failed\n");
+		goto fail; /* memory allocation failed */
+	}
+	res = tmp;
+	res[n_spaces] = 0;
+	return res;
+fail:
+	kfree(res);
+	return res;
+}
+
+/**
+ * Write File.
+ *
+ * @note Configure the system by writing a configuration
+ * index to the device node /dev/ipa_test
+ */
+ssize_t ipa_test_write(struct file *filp, const char __user *buf,
+		       size_t size, loff_t *f_pos)
+{
+	int ret = 0;
+	int index;
+
+	unsigned long missing;
+	char *str;
+	char **params;
+
+	str = kzalloc(size+1, GFP_KERNEL);
+	if (str == NULL) {
+		IPATEST_ERR("kzalloc err.\n");
+		return -ENOMEM;
+	}
+
+	missing = copy_from_user(str, buf, size);
+	if (missing) {
+		kfree(str);
+		return -EFAULT;
+	}
+	IPATEST_DBG("ipa_test_write: input string= %s\n", str);
+	str[size] = '\0';
+
+	params = str_split(str, " ");
+	if (params == NULL) {
+		kfree(str);
+		return -EFAULT;
+	}
+
+	ret = kstrtos32(params[0], 10, (s32 *)&ipa_test->configuration_idx);
+	if (ret) {
+		IPATEST_ERR("kstrtoul() failed.\n");
+		ret = -EFAULT;
+		goto bail;
+	}
+
+	IPATEST_DBG(":Invoking configuration %d.\n",
+			ipa_test->configuration_idx);
+
+	/* Setup GSI */
+
+	switch (ipa_test->configuration_idx) {
+	case -1:
+		destroy_channel_devices();
+		/*exception_hdl_exit();TODO: hsnapy un-comment this*/
+		break;
+
+	case 2:
+		index = 0;
+		ret = create_channel_device(index,
+					    "to_ipa", &to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->tx_channels[ipa_test->num_tx_channels++] =
+			to_ipa_devs[index];
+		ret = create_channel_device(index, "from_ipa",
+					    &from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->rx_channels[ipa_test->num_rx_channels++] =
+			from_ipa_devs[index];
+
+		index++;
+		ret = create_channel_device(index,
+					    "to_ipa", &to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->tx_channels[ipa_test->num_tx_channels++] =
+			to_ipa_devs[index];
+		ret = create_channel_device(index, "from_ipa",
+					    &from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->rx_channels[ipa_test->num_rx_channels++] =
+			from_ipa_devs[index];
+
+		index++;
+		ret = create_channel_device(index, "from_ipa",
+					    &from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->rx_channels[ipa_test->num_rx_channels++] =
+			from_ipa_devs[index];
+
+		ret = configure_system_2();
+		if (ret) {
+			IPATEST_ERR("System configuration failed.");
+			ret = -ENODEV;
+			goto bail;
+		}
+		break;
+
+	case 5:
+		index = 0;
+		ret = create_channel_device(index, "to_ipa",
+						&to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+
+		index++;
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+
+		index++;
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+
+		ret = configure_system_5();
+		if (ret) {
+			IPATEST_ERR("System configuration failed.");
+			ret = -ENODEV;
+			goto bail;
+		}
+		break;
+
+	case 6:
+		index = 0;
+		ret = create_channel_device(index, "to_ipa",
+						&to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+
+		ret = configure_system_6();
+		if (ret) {
+			IPATEST_ERR("System configuration failed.");
+			ret = -ENODEV;
+			goto bail;
+		}
+		break;
+
+	case 7:
+		index = 0;
+		ret = create_channel_device(index, "to_ipa",
+						&to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+
+		index++;
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+
+		index++;
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+
+		ret = configure_system_7();
+		if (ret) {
+			IPATEST_ERR("System configuration failed.");
+			ret = -ENODEV;
+			goto bail;
+		}
+		break;
+
+	case 8:
+		index = 0;
+		ret = create_channel_device(index, "to_ipa",
+						&to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+		index++;
+
+		ret = create_channel_device(index, "to_ipa",
+						&to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+		index++;
+
+		ret = create_channel_device(index, "to_ipa",
+						&to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+		index++;
+
+		ret = create_channel_device(index, "to_ipa",
+						&to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+
+		index = 0;
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+		index++;
+
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+		index++;
+
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+
+		ret = configure_system_8();
+		if (ret) {
+			IPATEST_ERR("System configuration failed.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		break;
+
+	case 9:
+		index = 0;
+		ret = create_channel_device(index, "to_ipa",
+						&to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+		index++;
+
+		ret = create_channel_device(index, "to_ipa",
+						&to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+		index++;
+
+		ret = create_channel_device(index, "to_ipa",
+						&to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+		index++;
+
+		ret = create_channel_device(index, "to_ipa",
+						&to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+
+		index = 0;
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+		index++;
+
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+		index++;
+
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+
+		ret = configure_system_9();
+		if (ret) {
+			IPATEST_ERR("System configuration failed.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		break;
+
+	case 10:
+		index = 0;
+		ret = create_channel_device(index, "to_ipa",
+				&to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+
+		index = 0;
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+
+		ret = configure_system_10();
+		if (ret) {
+			IPATEST_ERR("System configuration failed.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		break;
+
+	case 12:
+		index = 0;
+		ret = create_channel_device(index, "to_ipa",
+						&to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+		index++;
+
+		ret = create_channel_device(index, "to_ipa",
+						&to_ipa_devs[index],
+					    TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+
+		index = 0;
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+		index++;
+
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+		index++;
+
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+		index++;
+
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+				rx_channels[ipa_test->num_rx_channels++] =
+						from_ipa_devs[index];
+
+		ret = configure_system_12();
+		if (ret) {
+			IPATEST_ERR("System configuration failed.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		break;
+
+	case 18:
+		index = 0;
+		ret = create_channel_device(index, "to_ipa",
+					&to_ipa_devs[index], TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			return -ENODEV;
+		}
+		ipa_test->
+			tx_channels[ipa_test->num_tx_channels++] =
+						to_ipa_devs[index];
+
+		index++;
+		ret = create_channel_device_by_type(index, "to_ipa",
+					&to_ipa_devs[index], RX_SZ,
+					IPA_TEST_DATA_PATH_TEST_CHANNEL);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			return -ENODEV;
+		}
+		ipa_test->
+			tx_channels[ipa_test->num_tx_channels++] =
+					to_ipa_devs[index];
+
+		index = 0;
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index], RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			return -ENODEV;
+		}
+		ipa_test->
+			rx_channels[ipa_test->num_rx_channels++] =
+				from_ipa_devs[index];
+
+		ret = configure_system_18();
+		if (ret) {
+			IPATEST_ERR("System configuration failed.");
+			return -ENODEV;
+		}
+		break;
+
+	case 19:
+		index = 0;
+		/*Create the device on user space and allocate
+		 * buffers for its GSI connection*/
+		ret = create_channel_device(index, "to_ipa",
+				&to_ipa_devs[index], TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+			tx_channels[ipa_test->num_tx_channels++] =
+					to_ipa_devs[index];
+
+		/*Create the device on user space and allocate
+		 *  buffers for its GSI connection*/
+		ret = create_channel_device(index, "from_ipa",
+						&from_ipa_devs[index],
+					    RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->rx_channels[ipa_test->num_rx_channels++] =
+				from_ipa_devs[index];
+
+		/*Make all the configurations required
+		 * (IPA connect)*/
+		ret = configure_system_19();
+		if (ret) {
+			IPATEST_ERR("System configuration failed.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		break;
+
+	case 20:
+
+		/* Create producer channel 0 */
+		index = 0;
+		ret = create_channel_device(index,
+			"to_ipa", &to_ipa_devs[index],
+			TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+			tx_channels[ipa_test->num_tx_channels++] =
+			to_ipa_devs[index];
+
+
+		/* Create producer channel 1 */
+		index++;
+		ret = create_channel_device(index,
+			"to_ipa", &to_ipa_devs[index],
+			TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+			tx_channels[ipa_test->num_tx_channels++] =
+			to_ipa_devs[index];
+
+		/* Create producer channel 2 */
+		index++;
+		ret = create_channel_device(index,
+			"to_ipa", &to_ipa_devs[index],
+			TX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+			tx_channels[ipa_test->num_tx_channels++] =
+			to_ipa_devs[index];
+
+		/* Create consumer channel 0 */
+		index = 0;
+		ret = create_channel_device(index, "from_ipa",
+			&from_ipa_devs[index],
+			RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+			rx_channels[ipa_test->num_rx_channels++] =
+			from_ipa_devs[index];
+
+		/* Create consumer channel 1 */
+		index++;
+		ret = create_channel_device(index, "from_ipa",
+			&from_ipa_devs[index],
+			RX_SZ);
+		if (ret) {
+			IPATEST_ERR("Channel device creation error.\n");
+			ret = -ENODEV;
+			goto bail;
+		}
+		ipa_test->
+			rx_channels[ipa_test->num_rx_channels++] =
+			from_ipa_devs[index];
+
+		ret = configure_system_20();
+		if (ret) {
+			IPATEST_ERR("System configuration failed.");
+			ret = -ENODEV;
+			goto bail;
+		}
+		break;
+
+	default:
+		IPATEST_ERR("Unsupported configuration index.\n");
+		break;
+	}
+
+	/* Insert descriptors into the receiving end(s) */
+	ret = insert_descriptors_into_rx_endpoints(RX_BUFF_SIZE);
+	if (ret) {
+		IPATEST_DBG("Descriptor insertion into rx "
+			"endpoints failed.\n");
+		ret = -EINVAL;
+		goto bail;
+	}
+
+	IPATEST_DBG("System configured !\n");
+
+	/* Set the current configuration index */
+	ipa_test->current_configuration_idx	=
+		ipa_test->configuration_idx;
+
+	ret = size;
+
+bail:
+	kfree(params);
+	kfree(str);
+	return ret;
+}
+
+static ssize_t ipa_test_read(struct file *filp,
+		char __user *buf,
+		size_t count, loff_t *f_pos)
+{
+	int res, len;
+	char str[10];
+
+	if (0 != *f_pos) {
+		*f_pos = 0;
+		return 0;
+	}
+
+	/* Convert the configuration index to a null terminated string */
+	len = snprintf(str, 10, "%d",
+			ipa_test->current_configuration_idx);
+
+	IPATEST_DBG("str = %s, len = %d\n", str, len);
+
+	/* Copy the result to the user buffer */
+	res = copy_to_user(buf, str, len + 1);
+	if (res < 0) {
+		IPATEST_ERR("copy_to_user() failed.\n");
+		return -EFAULT;
+	}
+
+	/* Increment the file position pointer */
+	*f_pos += len;
+
+	/* Return the number of bytes copied to the user */
+	return len + 1;
+}
+
+static struct class *ipa_test_class;
+
+//TODO make only one configuration function
+static int configure_app_to_ipa_path(struct ipa_channel_config __user *to_ipa_user)
+{
+	int retval;
+	struct ipa_channel_config to_ipa_channel_config = {0};
+	struct ipa_sys_connect_params sys_in;
+	unsigned long ipa_gsi_hdl;
+	u32 ipa_pipe_num;
+	int index;
+
+	IPATEST_DBG("copying from 0x%px %zu bytes\n",
+		to_ipa_user,
+		sizeof(struct ipa_channel_config));
+	retval = copy_from_user(
+		&to_ipa_channel_config,
+		to_ipa_user,
+		sizeof(struct ipa_channel_config));
+	if (retval) {
+		IPATEST_ERR("fail to copy from user - to_ipa_user\n");
+		return -1;
+	}
+
+	index = to_ipa_channel_config.index;
+
+	IPATEST_DBG("to_ipa head_marker value is 0x%x\n",
+		to_ipa_channel_config.head_marker);
+
+	IPATEST_DBG("to_ipa config_size value is %zu\n",
+		to_ipa_channel_config.config_size);
+
+	IPATEST_DBG("to_ipa index value is %d\n", index);
+
+	IPATEST_DBG("client=%d\n",
+		to_ipa_channel_config.client);
+
+	IPATEST_DBG("to_ipa tail_marker value is 0x%x\n",
+		to_ipa_channel_config.tail_marker);
+
+	if (to_ipa_channel_config.head_marker !=
+		IPA_TEST_CHANNEL_CONFIG_MARKER) {
+		IPATEST_ERR("bad head_marker - possible memory corruption\n");
+		return -EFAULT;
+	}
+
+	if (to_ipa_channel_config.tail_marker !=
+		IPA_TEST_CHANNEL_CONFIG_MARKER) {
+		IPATEST_ERR("bad tail_marker - possible memory corruption\n");
+		return -EFAULT;
+	}
+
+	if (to_ipa_channel_config.config_size != sizeof(struct ipa_ep_cfg)) {
+		IPATEST_ERR("bad config size (%zu.vs.%zu) update test struct?\n",
+			to_ipa_channel_config.config_size,
+			sizeof(struct ipa_ep_cfg));
+		return -EFAULT;
+	}
+
+	/* Channel from which the userspace shall communicate to this pipe */
+	retval = create_channel_device(index, "to_ipa",
+				&to_ipa_devs[index], TX_SZ);
+	if (retval) {
+		IPATEST_ERR("channel device creation error\n");
+		return -1;
+	}
+	ipa_test->tx_channels[ipa_test->num_tx_channels++] =
+				to_ipa_devs[index];
+
+	/* Connect IPA --> Apps */
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = to_ipa_channel_config.client;
+	IPATEST_DBG("copying from 0x%px\n", to_ipa_channel_config.cfg);
+	retval = copy_from_user(
+		&sys_in.ipa_ep_cfg,
+		to_ipa_channel_config.cfg,
+		to_ipa_channel_config.config_size);
+	if (retval) {
+		IPATEST_ERR("fail to copy cfg - from_ipa_user\n");
+		return -1;
+	}
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&to_ipa_devs[index]->ipa_client_hdl, false)) {
+		IPATEST_ERR("setup sys pipe failed\n");
+		return -1;
+	}
+
+	/* Connect APPS MEM --> Tx IPA */
+	retval = connect_apps_to_ipa(&to_ipa_devs[index]->ep,
+				to_ipa_channel_config.client,
+				ipa_pipe_num,
+				&to_ipa_devs[index]->mem,
+				ipa_gsi_hdl);
+	if (retval) {
+		IPATEST_ERR("fail to connect ipa to apps\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int configure_app_from_ipa_path(struct ipa_channel_config __user *from_ipa_user)
+{
+	int retval;
+	struct ipa_channel_config from_ipa_channel_config = {0};
+	struct ipa_sys_connect_params sys_in;
+	unsigned long ipa_gsi_hdl;
+	u32 ipa_pipe_num;
+	int index;
+
+	IPATEST_DBG("copying from 0x%px %zu bytes\n",
+		from_ipa_user,
+		sizeof(struct ipa_channel_config));
+	retval = copy_from_user(
+		&from_ipa_channel_config,
+		from_ipa_user,
+		sizeof(struct ipa_channel_config));
+	if (retval) {
+		IPATEST_ERR("fail to copy from user - from_ipa_user (%d.vs.%zu)\n",
+			retval, sizeof(from_ipa_user));
+		return -1;
+	}
+
+	index = from_ipa_channel_config.index;
+
+	IPATEST_DBG("from_ipa head_marker value is 0x%x\n",
+		from_ipa_channel_config.head_marker);
+
+	IPATEST_DBG("from_ipa config_size value is %zu\n",
+		from_ipa_channel_config.config_size);
+
+	IPATEST_DBG("from_ipa index value is %d\n",
+		index);
+
+	IPATEST_DBG("client=%d\n",
+		from_ipa_channel_config.client);
+
+	IPATEST_DBG("from_ipa tail_marker value is 0x%x\n",
+		from_ipa_channel_config.tail_marker);
+
+	if (from_ipa_channel_config.head_marker !=
+		IPA_TEST_CHANNEL_CONFIG_MARKER) {
+		IPATEST_ERR("bad head_marker - possible memory corruption\n");
+		return -EFAULT;
+	}
+
+	if (from_ipa_channel_config.tail_marker !=
+		IPA_TEST_CHANNEL_CONFIG_MARKER) {
+		IPATEST_ERR("bad tail_marker - possible memory corruption\n");
+		return -EFAULT;
+	}
+
+	if (from_ipa_channel_config.config_size != sizeof(struct ipa_ep_cfg)) {
+		IPATEST_ERR("bad config size (%zu.vs.%zu) update test struct?\n",
+			from_ipa_channel_config.config_size,
+			sizeof(struct ipa_ep_cfg));
+		return -EFAULT;
+	}
+
+	/* Channel from which the userspace shall communicate to this pipe */
+	retval = create_channel_device(index, "from_ipa",
+			&from_ipa_devs[index], RX_SZ);
+	if (retval) {
+		IPATEST_ERR("channel device creation error\n");
+		return -1;
+	}
+	ipa_test->rx_channels[ipa_test->num_rx_channels++] =
+			from_ipa_devs[index];
+
+	/* Connect IPA --> Apps */
+	IPATEST_DBG("copying from 0x%px\n", from_ipa_channel_config.cfg);
+	memset(&sys_in, 0, sizeof(sys_in));
+	sys_in.client = from_ipa_channel_config.client;
+	retval = copy_from_user(
+		&sys_in.ipa_ep_cfg,
+		from_ipa_channel_config.cfg,
+		from_ipa_channel_config.config_size);
+	if (retval) {
+		IPATEST_ERR("fail to copy cfg - from_ipa_user\n");
+		return -1;
+	}
+
+	if (ipa3_sys_setup(&sys_in, &ipa_gsi_hdl, &ipa_pipe_num,
+			&from_ipa_devs[index]->ipa_client_hdl, from_ipa_channel_config.en_status)) {
+			IPATEST_ERR("setup sys pipe failed\n");
+			return -1;
+	}
+
+	retval = connect_ipa_to_apps(&from_ipa_devs[index]->ep,
+				from_ipa_channel_config.client,
+				ipa_pipe_num,
+				ipa_gsi_hdl);
+	if (retval) {
+		IPATEST_ERR("fail to connect ipa to apps\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int configure_test_scenario(
+		struct ipa_test_config_header *ipa_test_config_header,
+		struct ipa_channel_config **from_ipa_channel_config_array,
+		struct ipa_channel_config **to_ipa_channel_config_array)
+{
+	int retval;
+	int i;
+
+	if (ipa_test->num_tx_channels > 0 || ipa_test->num_rx_channels >0) {
+		IPATEST_DBG("cleanning previous configuration before new one\n");
+		destroy_channel_devices();
+	} else {
+		IPATEST_DBG("system is clean, starting new configuration");
+	}
+
+	IPATEST_DBG("starting scenario configuration\n");
+
+	IPATEST_DBG("head_marker value is 0x%x\n",
+		ipa_test_config_header->head_marker);
+
+	IPATEST_DBG("from_ipa_channels_num=%d\n\n",
+		ipa_test_config_header->from_ipa_channels_num);
+
+	IPATEST_DBG("to_ipa_channels_num=%d\n\n",
+		ipa_test_config_header->to_ipa_channels_num);
+
+	IPATEST_DBG("tail_marker value is 0x%x\n",
+		ipa_test_config_header->tail_marker);
+
+	if (ipa_test_config_header->head_marker != IPA_TEST_CONFIG_MARKER) {
+		IPATEST_ERR("bad header marker - possible memory corruption\n");
+		return -EFAULT;
+	}
+
+	if (ipa_test_config_header->tail_marker != IPA_TEST_CONFIG_MARKER) {
+		IPATEST_ERR("bad tail marker - possible memory corruption\n");
+		return -EFAULT;
+	}
+
+	for (i = 0 ; i < ipa_test_config_header->from_ipa_channels_num ; i++) {
+		IPATEST_DBG("starting configuration of from_ipa_%d\n", i);
+		retval = configure_app_from_ipa_path(
+			from_ipa_channel_config_array[i]);
+		if (retval) {
+			IPATEST_ERR("fail to configure from_ipa_%d", i);
+			goto fail;
+		}
+	}
+
+	retval = insert_descriptors_into_rx_endpoints(RX_BUFF_SIZE);
+	if (retval) {
+		IPATEST_ERR("RX descriptors failed\n");
+		goto fail;
+	}
+	IPATEST_DBG("RX descriptors were added to RX pipes\n");
+
+	for (i = 0 ; i < ipa_test_config_header->to_ipa_channels_num ; i++) {
+		retval = configure_app_to_ipa_path(
+			to_ipa_channel_config_array[i]);
+		if (retval) {
+			IPATEST_ERR("fail to configure to_ipa_%d", i);
+			goto fail;
+		}
+	}
+
+	/*
+	 * This value is arbitrary, it is used in
+	 * order to be able to cleanup
+	 */
+	ipa_test->current_configuration_idx = GENERIC_TEST_CONFIGURATION_IDX;
+
+	IPATEST_DBG("finished scenario configuration\n");
+
+	return 0;
+fail:
+	destroy_channel_devices();
+
+	return retval;
+}
+
+static int handle_configuration_ioctl(unsigned long ioctl_arg)
+{
+	int retval;
+	int needed_bytes;
+	struct ipa_test_config_header test_header;
+	struct ipa_channel_config **from_ipa_channel_config_array;
+	struct ipa_channel_config **to_ipa_channel_config_array;
+
+	/* header copy */
+	IPATEST_DBG("copying from 0x%px\n", (u8 *)ioctl_arg);
+	retval = copy_from_user(&test_header,
+			(u8 *)ioctl_arg,
+			sizeof(test_header));
+	if (retval) {
+		IPATEST_ERR("failing copying header from user\n");
+		return retval;
+	}
+
+	/* allocate place for the configuration array for "from" */
+	needed_bytes = test_header.from_ipa_channels_num*
+		sizeof(*test_header.from_ipa_channel_config);
+
+	from_ipa_channel_config_array = kzalloc(needed_bytes, GFP_KERNEL);
+	if (!from_ipa_channel_config_array) {
+		IPATEST_ERR("fail mem alloc for from_ipa\n");
+		retval = -ENOMEM;
+		goto fail_from_alloc;
+	}
+
+	/* copy the configuration array for "from" */
+	IPATEST_DBG("copying from 0x%px\n", test_header.from_ipa_channel_config);
+	retval = copy_from_user(from_ipa_channel_config_array,
+			test_header.from_ipa_channel_config,
+			needed_bytes);
+	if (retval) {
+		IPATEST_ERR("failing copying to_ipa from user\n");
+		goto fail_copy_from;
+	}
+
+	/* allocate place for the configuration array for "from" */
+	needed_bytes = test_header.to_ipa_channels_num*
+		sizeof(*test_header.to_ipa_channel_config);
+
+	to_ipa_channel_config_array = kzalloc(needed_bytes, GFP_KERNEL);
+	if (!to_ipa_channel_config_array) {
+		IPATEST_ERR("fail mem alloc for to_ipa\n");
+		goto fail_to_alloc;
+	}
+
+	/* copy the configuration array for "to" */
+	IPATEST_DBG("copying from 0x%px\n", test_header.to_ipa_channel_config);
+	retval = copy_from_user(to_ipa_channel_config_array,
+			test_header.to_ipa_channel_config,
+			needed_bytes);
+	if (retval) {
+		IPATEST_ERR("failing copying to_ipa from user\n");
+		goto fail_copy_to;
+	}
+
+	retval = configure_test_scenario(
+			&test_header,
+			from_ipa_channel_config_array,
+			to_ipa_channel_config_array);
+	if (retval)
+		IPATEST_ERR("fail to configure the system\n");
+
+fail_copy_to:
+	kfree(to_ipa_channel_config_array);
+fail_to_alloc:
+fail_copy_from:
+	kfree(from_ipa_channel_config_array);
+fail_from_alloc:
+	return retval;
+
+}
+
+int handle_clean_ioctl(void)
+{
+	IPATEST_DBG("cleanning previous configuration\n");
+	destroy_channel_devices();
+
+	return 0;
+}
+
+static int handle_ep_ctrl_ioctl(unsigned long ioctl_arg)
+{
+	int retval = 0;
+	struct ipa_ep_cfg_ctrl ep_ctrl;
+	struct ipa_test_ep_ctrl test_ep_ctrl;
+
+	retval = copy_from_user(&test_ep_ctrl,
+			(u8 *)ioctl_arg,
+			sizeof(test_ep_ctrl));
+	if (retval) {
+		IPATEST_ERR("failed copying ep_ctrl data from user\n");
+		return retval;
+	}
+
+	ep_ctrl.ipa_ep_delay = test_ep_ctrl.ipa_ep_delay;
+	ep_ctrl.ipa_ep_suspend = test_ep_ctrl.ipa_ep_suspend;
+
+	/* pipe suspend is not supported in IPA_v4 or higher */
+	if(ipa_get_hw_type() >= IPA_HW_v4_0){
+		if(ep_ctrl.ipa_ep_suspend)
+			retval = ipa_stop_gsi_channel(from_ipa_devs[test_ep_ctrl.from_dev_num]->ipa_client_hdl);
+		else
+			retval = gsi_start_channel(from_ipa_devs[test_ep_ctrl.from_dev_num]->ep.gsi_chan_hdl);
+
+		if (retval) {
+			IPATEST_ERR("failed closing/opening the GSI channel\n");
+			return retval;
+		}
+		ep_ctrl.ipa_ep_suspend = false;
+	}
+
+	IPATEST_DBG("handle_ep_ctrl_ioctl: sending hdl %d\n\n",
+			from_ipa_devs[test_ep_ctrl.from_dev_num]->ipa_client_hdl);
+
+	return ipa_cfg_ep_ctrl(from_ipa_devs[test_ep_ctrl.from_dev_num]->ipa_client_hdl, &ep_ctrl);
+}
+
+static int handle_reg_suspend_handler(unsigned long ioctl_arg)
+{
+	int res = 0;
+	struct ipa_tx_suspend_private_data *suspend_priv_data = NULL;
+	struct ipa_test_reg_suspend_handler reg_data;
+
+	res = copy_from_user(&reg_data,
+			(u8 *)ioctl_arg,
+			sizeof(reg_data));
+	if (res) {
+		IPATEST_ERR("failed copying ep_ctrl data from user\n");
+		return res;
+	}
+
+	if (reg_data.reg) {
+		if (reg_data.DevNum >= (MAX_CHANNEL_DEVS / 2))
+		{
+			res = -ENXIO;
+			IPATEST_ERR("DevNum is incorrect %d\n", reg_data.DevNum);
+			goto fail;
+		}
+
+		suspend_priv_data =
+				kzalloc(sizeof(*suspend_priv_data), GFP_KERNEL);
+		if (!suspend_priv_data) {
+			IPATEST_ERR("failed allocating suspend_priv_data\n");
+			res = -ENOMEM;
+			goto fail;
+		}
+
+		suspend_priv_data->clnt_hdl = from_ipa_devs[reg_data.DevNum]->ipa_client_hdl;
+		suspend_priv_data->gsi_chan_hdl = from_ipa_devs[reg_data.DevNum]->ep.gsi_chan_hdl;
+		IPATEST_DBG("registering interrupt handle to clnt_hdl %d\n", suspend_priv_data->clnt_hdl);
+		res = ipa_add_interrupt_handler(IPA_TX_SUSPEND_IRQ, suspend_handler,
+				reg_data.deferred_flag, (void *)suspend_priv_data);
+		if (res) {
+			IPATEST_ERR("register handler for suspend interrupt failed\n");
+			goto fail_allocated;
+		}
+
+	} else {
+		res = ipa_restore_suspend_handler();
+	}
+fail:
+	return res;
+fail_allocated:
+	kfree(suspend_priv_data);
+	return res;
+}
+
+static int handle_holb_config_ioctl(unsigned long ioctl_arg)
+{
+	int retval = 0;
+	int clnt_hdl;
+	struct ipa_ep_cfg_holb holb_cfg = {0};
+	struct ipa_test_holb_config test_holb_config;
+
+	retval = copy_from_user(&test_holb_config,
+			(u8 *)ioctl_arg,
+			sizeof(test_holb_config));
+	if (retval) {
+		IPATEST_ERR("failed copying holb_config data from user\n");
+		return retval;
+	}
+
+	clnt_hdl = ipa_get_ep_mapping(test_holb_config.client);
+
+	IPATEST_ERR("Sending clnt_hdl %d", clnt_hdl);
+
+	holb_cfg.en = test_holb_config.en;
+	holb_cfg.tmr_val = test_holb_config.tmr_val;
+
+	return ipa3_cfg_ep_holb(clnt_hdl, &holb_cfg);
+}
+
+static long ipa_test_ioctl(struct file *filp,
+	unsigned int cmd, unsigned long arg)
+{
+	int retval;
+
+	IPATEST_DBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
+	if (_IOC_TYPE(cmd) != IPA_TEST_IOC_MAGIC)
+		return -ENOTTY;
+
+	switch (cmd) {
+	case IPA_TEST_IOC_CONFIGURE:
+		retval = handle_configuration_ioctl(arg);
+		break;
+
+	case IPA_TEST_IOC_CLEAN:
+		retval = handle_clean_ioctl();
+		break;
+
+	case IPA_TEST_IOC_GET_HW_TYPE:
+		retval = ipa_get_hw_type();
+		break;
+	case IPA_TEST_IOC_EP_CTRL:
+		retval = handle_ep_ctrl_ioctl(arg);
+		break;
+	case IPA_TEST_IOC_REG_SUSPEND_HNDL:
+		retval = handle_reg_suspend_handler(arg);
+		break;
+	case IPA_TEST_IOC_HOLB_CONFIG:
+		retval = handle_holb_config_ioctl(arg);
+		break;
+	default:
+		IPATEST_ERR("ioctl is not supported (%d)\n", cmd);
+		return -ENOTTY;
+	}
+
+	return retval;
+}
+
+static int ipa_test_open(struct inode *inode, struct file *file)
+{
+	IPATEST_DBG("ipa_test module opened by %s\n", current->comm);
+	return 0;
+}
+
+static int ipa_test_release(struct inode *inode, struct file *file)
+{
+	IPATEST_DBG("ipa_test module closed by %s\n", current->comm);
+	return 0;
+}
+
+
+static const struct file_operations ipa_test_fops = {
+	.owner = THIS_MODULE,
+	.write = ipa_test_write,
+	.read  = ipa_test_read,
+	.open  = ipa_test_open,
+	.release  = ipa_test_release,
+	.unlocked_ioctl = ipa_test_ioctl,
+};
+
+/**
+ * Module Init.
+ */
+static int __init ipa_test_init(void)
+{
+	int ret;
+
+	IPATEST_DBG("IPA test driver load...\n");
+
+	ipa_test = kzalloc(sizeof(*ipa_test), GFP_KERNEL);
+	if (ipa_test == NULL) {
+		IPATEST_ERR("kzalloc err.\n");
+		return -ENOMEM;
+	}
+	ipa_test->signature = TEST_SIGNATURE;
+	ipa_test->current_configuration_idx = -1;
+
+	ipa_test_class = class_create(THIS_MODULE, IPA_TEST_DRV_NAME);
+
+	ret = alloc_chrdev_region(&ipa_test->dev_num, 0, 1, IPA_TEST_DRV_NAME);
+	if (ret) {
+		IPATEST_ERR("alloc_chrdev_region err.\n");
+		return -ENODEV;
+	}
+
+	ipa_test->dev = device_create(ipa_test_class, NULL,
+					ipa_test->dev_num,
+				      ipa_test, IPA_TEST_DRV_NAME);
+	if (IS_ERR(ipa_test->dev)) {
+		IPATEST_ERR("device_create err.\n");
+		return -ENODEV;
+	}
+
+	ipa_test->cdev = cdev_alloc();
+	if (ipa_test->cdev == NULL) {
+		IPATEST_ERR("cdev_alloc err.\n");
+		return -ENODEV;
+	}
+
+	cdev_init(ipa_test->cdev, &ipa_test_fops);
+	ipa_test->cdev->owner = THIS_MODULE;
+
+	ret = cdev_add(ipa_test->cdev, ipa_test->dev_num, 1);
+	if (ret)
+		IPATEST_ERR("cdev_add err=%d\n", -ret);
+
+	if (ret == 0)
+		IPATEST_DBG("IPA Test init OK, waiting for configuration index.\n");
+	else
+		IPATEST_DBG("IPA Test init FAIL.\n");
+
+	ret = datapath_ds_init();
+	if (ret != 0)
+		IPATEST_DBG("datapath_ds_init() failed (%d)\n", ret);
+
+	return ret;
+}
+
+/**
+ * Module Exit.
+ */
+static void __exit ipa_test_exit(void)
+{
+	IPATEST_DBG("ipa_test_exit.\n");
+
+	exception_hdl_exit(); /* Clear the Exception Device and KFIFO*/
+
+	datapath_exit();
+
+	destroy_channel_devices();
+
+	cdev_del(ipa_test->cdev);
+	device_destroy(ipa_test_class, ipa_test->dev_num);
+	class_destroy(ipa_test_class);
+	unregister_chrdev_region(ipa_test->dev_num, 1);
+
+	kfree(ipa_test);
+
+	IPATEST_DBG("ipa_test_exit complete.\n");
+}
+
+module_init(ipa_test_init);
+module_exit(ipa_test_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("IPA Testing");

+ 8 - 0
drivers/platform/msm/ipa/ipa_v3/ipa_i.h

@@ -2932,6 +2932,14 @@ bool ipa3_get_lan_rx_napi(void);
 
 bool ipa3_get_qmap_pipe_enable(void);
 
+struct device *ipa3_get_pdev(void);
+int ipa3_sys_update_gsi_hdls(u32 clnt_hdl, unsigned long gsi_ch_hdl,
+	unsigned long gsi_ev_hdl);
+int ipa3_sys_setup(struct ipa_sys_connect_params *sys_in,
+			unsigned long *ipa_transport_hdl,
+			u32 *ipa_pipe_num, u32 *clnt_hdl, bool en_status);
+int ipa3_sys_teardown(u32 clnt_hdl);
+
 /* internal functions */
 
 u8 ipa3_get_hw_type_index(void);

+ 2 - 1
drivers/platform/msm/ipa/ipa_v3/ipa_rt.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/bitops.h>
@@ -2108,6 +2108,7 @@ ret:
 
 	return result;
 }
+EXPORT_SYMBOL(ipa3_get_rt_tbl);
 
 /**
  * ipa3_put_rt_tbl() - Release the specified routing table handle

+ 395 - 0
kernel-tests/Constants.h

@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2017,2019 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef CONSTANTS_H_
+#define CONSTANTS_H_
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#define PRE_PHASE_ZERO_TEST_CONFIGURATION 0
+/*----------------------------------------------------------------------
+ *Configuration 1 (see configure_system_1 )
+ *-----USB_PROD--->[IPA DMA]----USB_CONS--->
+ *----------------------------------------------------------------------
+ */
+#define PHASE_ZERO_TEST_CONFIGURATION	  1
+/*----------------------------------------------------------------------
+ *Configuration 2 (see configure_system_2 )
+ *					[IPA]----USB2_CONS-->
+ *-----USB_PROD--->[IPA]----USB3_CONS--->
+ *					[IPA]----USB4_CONS--->
+ *----------------------------------------------------------------------
+ */
+#define PHASE_TWO_TEST_CONFIGURATION      2
+/*----------------------------------------------------------------------
+ *Configuration 3 (see configure_system_3 )
+ *					[IPA]----USB_CONS------>
+ *-----USB2_PROD--->[IPA]----USB2_CONS--->
+ *					[IPA]----USB4_CONS---->
+ *----------------------------------------------------------------------
+ */
+#define PHASE_THREE_TEST_CONFIGURATION    3
+/*Configuration 5 (see configure_system_5 )
+ *					[IPA]----USB2_CONS + Header Insertion (6Bytes) -->
+ *-----USB_PROD--->[IPA]----USB3_CONS +
+ *Header Insertion (22Bytes) + Length offset (11Bytes) -->
+ *					[IPA]----USB4_CONS +
+ *Header Insertion (22Bytes) + Length offset (11Bytes) + Const(1Byte)-->
+ */
+
+/* This Cfg is only for USB Integration Phase I*/
+#define PHASE_FIVE_TEST_CONFIGURATION	  5
+#define PHASE_SIX_TEST_CONFIGURATION	  6
+/*Configuration 7 (see configure_system_7 )
+ *                  [IPA]----USB2_CONS-->
+ *-----USB_PROD--->[IPA]----USB3_CONS--->
+ *                  [IPA]----USB4_CONS--->
+ *                  [IPA]----A5 - Exception Pipe--->
+ */
+#define PHASE_SEVEN_TEST_CONFIGURATION    7
+/*----------------------------------------------------------------------
+ *Configuration 8 (see configure_system_8 )
+ *-----USB3_CONS--->[IPA DMA]----USB_CONS (TLP aggregation byte limit)--->
+ *-----USB_PROD (TLP deaggregation)--->[IPA DMA]----USB3_CONS--->
+ *-----USB2_PROD (TLP deaggregation)--->
+ *-----[IPA DMA]----USB_CONS (TLP aggregation byte limit)--->
+ *-----USB4_PROD--->[IPA DMA]----USB2_CONS (TLP aggregation time limit)--->
+ *----------------------------------------------------------------------
+ */
+#define PHASE_EIGHT_TEST_CONFIGURATION    8
+/*----------------------------------------------------------------------
+ *Configuration 9 (see configure_system_9 )
+ *-----USB3_PROD--->[IPA DMA]----USB_CONS (MBIM aggregation byte limit)--->
+ *-----USB_PROD (MBIM deaggregation)--->[IPA DMA]----USB3_CONS--->
+ *-----USB2_PROD (MBIM deaggregation)--->
+ *-----[IPA DMA]----USB_CONS (MBIM aggregation byte limit)--->
+ *-----USB4_PROD--->[IPA DMA]----USB2_CONS (MBIM aggregation time limit)--->
+ *----------------------------------------------------------------------
+ */
+#define PHASE_NINE_TEST_CONFIGURATION    9
+/*----------------------------------------------------------------------
+ *Configuration 10 (see configure_system_10 )
+ *-----USB_PROD--->[IPA DMA]----USB_CONS (MBIM aggregation no limits)--->
+ *----------------------------------------------------------------------
+ */
+#define PHASE_TEN_TEST_CONFIGURATION      10
+/*----------------------------------------------------------------------
+ *Configuration 11 (see configure_system_11 )
+ *-----USB_PROD----->[IPA]----
+ * USB2_CONS(MBIM aggregation byte limit)--->
+ *-USB2_PROD (MBIM deaggregation)->[IPA]----USB3_CONS--->
+ *------------------>[IPA]----
+ *USB_CONS (MBIM aggregation time limit)----------->
+ *------------------>[IPA]----
+ *A5_LAN_WAN_CONS (MBIM aggregation no limits)---->
+ *----------------------------------------------------------------------
+ */
+#define PHASE_ELEVEN_TEST_CONFIGURATION    11
+/*----------------------------------------------------------------------
+ *Configuration 12 (see configure_system_12 )
+ *-----USB_PROD----->[IPA]----USB2_CONS (MBIM aggregation byte limit)--->
+ *-USB2_PROD (MBIM deaggregation)->[IPA]----USB3_CONS--->
+ *------------------>[IPA]----
+ * USB_CONS (MBIM aggregation time limit)----------->
+ *------------------>[IPA]----
+ * A5_LAN_WAN_CONS (MBIM aggregation no limits)---->
+ *----------------------------------------------------------------------
+ */
+#define PHASE_TWELVE_TEST_CONFIGURATION		12
+/*----------------------------------------------------------------------
+ *Configuration 9 (see configure_system_17 )
+ *-----USB3_PROD--->[IPA DMA]----USB_CONS (RNDIS aggregation byte limit)--->
+ *-----USB_PROD (RNDIS deaggregation)--->[IPA DMA]----USB3_CONS--->
+ *-----USB2_PROD (RNDIS deaggregation)--->
+ *-----[IPA DMA]----USB_CONS (RNDIS aggregation byte limit)--->
+ *-----USB4--->[IPA DMA]----USB2_CONS (RNDIS aggregation time limit)--->
+ *----------------------------------------------------------------------
+ */
+#define PHASE_SEVENTEEN_TEST_CONFIGURATION    17
+
+/*
+ * Data path test
+ */
+#define PHASE_EIGHTEEN_TEST_CONFIGURATION 18
+
+/*----------------------------------------------------------------------
+ *Configuration 19 (see configure_system_19 )
+ *-----USB_PROD--->[IPA DMA]----USB_CONS--->
+ *-----suspend [IPA DMA]----USB_CONS (for testing suspend interrupt)--->
+ *----------------------------------------------------------------------
+ */
+#define PHASE_NINETEEN_TEST_CONFIGURATION 19
+
+#define PHASE_TWENTY_TEST_CONFIGURATION 20
+/*----------------------------------------------------------------------
+ *Configuration 20 (see configure_system_20 )
+ *-----PROD (WLAN header removal)--------------------->[IPA]----CONS---->
+ *-----PROD (RNDIS de-aggregation + Header removal)--->[IPA]
+ *----------------------------------------------------------------------
+ */
+
+enum IPATestConfiguration {
+	IPA_TEST_CONFIFURATION_0 = PRE_PHASE_ZERO_TEST_CONFIGURATION,
+	IPA_TEST_CONFIFURATION_1 = PHASE_ZERO_TEST_CONFIGURATION,
+	IPA_TEST_CONFIFURATION_2 = PHASE_TWO_TEST_CONFIGURATION,
+	IPA_TEST_CONFIFURATION_3 = PHASE_THREE_TEST_CONFIGURATION,
+	IPA_TEST_CONFIFURATION_5 = PHASE_FIVE_TEST_CONFIGURATION,
+	IPA_TEST_CONFIFURATION_6 = PHASE_SIX_TEST_CONFIGURATION,
+	IPA_TEST_CONFIFURATION_7 = PHASE_SEVEN_TEST_CONFIGURATION,
+	IPA_TEST_CONFIGURATION_8 = PHASE_EIGHT_TEST_CONFIGURATION,
+	IPA_TEST_CONFIGURATION_9 = PHASE_NINE_TEST_CONFIGURATION,
+	IPA_TEST_CONFIGURATION_10 = PHASE_TEN_TEST_CONFIGURATION,
+	IPA_TEST_CONFIGURATION_11 = PHASE_ELEVEN_TEST_CONFIGURATION,
+	IPA_TEST_CONFIGURATION_12 = PHASE_TWELVE_TEST_CONFIGURATION,
+	IPA_TEST_CONFIGURATION_17 = PHASE_SEVENTEEN_TEST_CONFIGURATION,
+	IPA_TEST_CONFIGURATION_18 = PHASE_EIGHTEEN_TEST_CONFIGURATION,
+	IPA_TEST_CONFIGURATION_19 = PHASE_NINETEEN_TEST_CONFIGURATION,
+	IPA_TEST_CONFIGURATION_20 = PHASE_NINETEEN_TEST_CONFIGURATION,
+};
+#define CONFIGURATION_NODE_PATH "/dev/ipa_test"
+
+/*producer*/
+#define INTERFACE0_TO_IPA_DATA_PATH			"/dev/to_ipa_0"
+#define INTERFACE0_FROM_IPA_DATA_PATH		NULL
+
+/*producer*/
+#define INTERFACE4_TO_IPA_DATA_PATH			"/dev/to_ipa_1"
+#define INTERFACE4_FROM_IPA_DATA_PATH		NULL
+
+/*producer*/
+#define INTERFACE5_TO_IPA_DATA_PATH			"/dev/to_ipa_2"
+#define INTERFACE5_FROM_IPA_DATA_PATH		NULL
+
+/*consumer*/
+#define INTERFACE1_TO_IPA_DATA_PATH			NULL
+#define INTERFACE1_FROM_IPA_DATA_PATH		"/dev/from_ipa_0"
+
+/*consumer 2*/
+#define INTERFACE2_TO_IPA_DATA_PATH			NULL
+#define INTERFACE2_FROM_IPA_DATA_PATH		"/dev/from_ipa_1"
+
+/*Default consumer*/
+#define INTERFACE3_TO_IPA_DATA_PATH			NULL
+#define INTERFACE3_FROM_IPA_DATA_PATH		"/dev/from_ipa_2"
+
+/*Exceptions producer*/
+#define INTERFACE_TO_IPA_EXCEPTION_PATH		NULL
+#define INTERFACE_FROM_IPA_EXCEPTION_PATH	"/dev/ipa_exception_pipe"
+
+/*The next configuration should be used by the ITAKEM as well.*/
+
+/*----------------------------------------------------------------------
+ *Configuration 1 (see configure_system_1 )
+ *-----USB_PROD--->[IPA DMA]----USB_CONS--->
+ *----------------------------------------------------------------------
+ */
+#define CONFIG_1_FROM_USB1_TO_IPA_DMA		"/dev/to_ipa_0"
+#define CONFIG_1_FROM_IPA_TO_USB1_DMA		"/dev/from_ipa_0"
+
+/*----------------------------------------------------------------------
+ *Configuration 2 (see configure_system_2 )
+ *                  [IPA]----USB2_CONS-->
+ *-----USB_PROD--->[IPA]----USB3_CONS--->
+ *                  [IPA]----Q6_LAN_CONS--->
+ *---------------------------------------------------------------------
+ */
+#define CONFIG_2_FROM_USB_TO_IPA            "/dev/to_ipa_0"
+#define CONFIG_2_FROM_IPA_TO_A2_NDUN        "/dev/from_ipa_0"
+#define CONFIG_2_FROM_IPA_TO_A2_DUN         "/dev/from_ipa_1"
+#define CONFIG_2_FROM_IPA_TO_Q6_LAN         "/dev/from_ipa_2"
+
+/*USB1 is an EthernetII Client*/
+#define FROM_USB1_TO_IPA				"/dev/to_ipa_0"
+#define FROM_IPA_TO_USB1				"/dev/from_ipa_0"
+#define USB1_CLIENT_HEADER_LENGTH		14
+
+/*----------------------------------------------------------------------
+ *Configuration 3 (see configure_system_3 )
+ *                     [IPA]----USB_CONS------>
+ *-----USB2_PROD--->[IPA]----USB2_CONS--->
+ *                     [IPA]----Q6_LAN_CONS---->
+ *----------------------------------------------------------------------
+ */
+#define CONFIG_3_FROM_A2_NDUN_TO_IPA            "/dev/to_ipa_0"
+#define CONFIG_3_FROM_IPA_TO_USB1               "/dev/from_ipa_0"
+#define CONFIG_3_FROM_IPA_TO_A2_NDUN            "/dev/from_ipa_1"
+#define CONFIG_3_FROM_IPA_TO_Q6_LAN             "/dev/from_ipa_2"
+
+/*----------------------------------------------------------------------
+ *Configuration 8 (see configure_system_8 )
+ *-----USB3_PROD--->[IPA DMA]----
+ *-----USB_CONS (TLP aggregation byte limit)--->
+ *-----USB_PROD (TLP deaggregation)--->[IPA DMA]----USB3_CONS--->
+ *-----USB2_PROD (TLP deaggregation)--->
+ * [IPA DMA]----USB_CONS (TLP aggregation byte limit)--->
+ *-----USB4--->[IPA DMA]----USB2_CONS (TLP aggregation time limit)--->
+ *----------------------------------------------------------------------
+ */
+#define CONFIG_8_NO_AGG_TO_IPA_AGG			"/dev/to_ipa_0"
+#define CONFIG_8_DEAGG_TO_IPA_NO_AGG		"/dev/to_ipa_1"
+#define CONFIG_8_DEAGG_TO_IPA_AGG			"/dev/to_ipa_2"
+#define CONFIG_8_NO_AGG_TO_IPA_AGG_TIME     "/dev/to_ipa_3"
+#define CONFIG_8_FROM_IPA_AGG				"/dev/from_ipa_0"
+#define CONFIG_8_FROM_IPA_NO_AGG			"/dev/from_ipa_1"
+#define CONFIG_8_DEAGG_FROM_IPA_AGG         "/dev/from_ipa_2"
+
+/*----------------------------------------------------------------------
+ *Configuration 9 (see configure_system_9 )
+ *-----USB3_PROD--->[IPA DMA]----
+ * USB_CONS (MBIM aggregation byte limit)--->
+ *-----USB_PROD (MBIM deaggregation)--->[IPA DMA]----USB3_CONS--->
+ *-----USB2_PROD (MBIM deaggregation)--->
+ * [IPA DMA]----USB_CONS (MBIM aggregation byte limit)--->
+ *-----USB4--->[IPA DMA]----
+ * USB2_CONS (MBIM aggregation time limit)--->
+ *----------------------------------------------------------------------
+ */
+#define CONFIG_9_NO_AGG_TO_IPA_AGG			"/dev/to_ipa_0"
+#define CONFIG_9_DEAGG_TO_IPA_NO_AGG		"/dev/to_ipa_1"
+#define CONFIG_9_DEAGG_TO_IPA_AGG			"/dev/to_ipa_2"
+#define CONFIG_9_NO_AGG_TO_IPA_AGG_TIME     "/dev/to_ipa_3"
+#define CONFIG_9_FROM_IPA_AGG				"/dev/from_ipa_0"
+#define CONFIG_9_FROM_IPA_NO_AGG			"/dev/from_ipa_1"
+#define CONFIG_9_DEAGG_FROM_IPA_AGG         "/dev/from_ipa_2"
+
+/*----------------------------------------------------------------------
+ *Configuration 10 (see configure_system_10 )
+ *-----USB_PROD--->[IPA DMA]----
+ *	USB_CONS (MBIM aggregation no limits)--->
+ *----------------------------------------------------------------------
+ */
+#define CONFIG_10_TO_IPA_AGG_ZERO_LIMITS		"/dev/to_ipa_0"
+#define CONFIG_10_FROM_IPA_AGG_ZERO_LIMITS		"/dev/from_ipa_0"
+
+/*----------------------------------------------------------------------
+ *Configuration 11 (see configure_system_11 )
+ *-----USB_PROD----->[IPA]----
+ * USB2_CONS (MBIM aggregation byte limit)--->
+ * USB2_PROD (MBIM deaggregation)->[IPA]----USB3_CONS--->
+ *------------------>[IPA]----
+ * USB_CONS (MBIM aggregation time limit)----------->
+ *------------------>[IPA
+ * A5_LAN_WAN_CONS (MBIM aggregation no limits)---->
+ *----------------------------------------------------------------------
+ */
+#define CONFIG_11_TO_IPA				"/dev/to_ipa_0"
+#define CONFIG_11_TO_IPA_DEAGG			"/dev/to_ipa_1"
+#define CONFIG_11_FROM_IPA_AGG			"/dev/from_ipa_0"
+#define CONFIG_11_FROM_IPA				"/dev/from_ipa_1"
+#define CONFIG_11_FROM_IPA_AGG_TIME		"/dev/from_ipa_2"
+#define CONFIG_11_FROM_IPA_ZERO_LIMITS	"/dev/from_ipa_3"
+
+/*----------------------------------------------------------------------
+ *Configuration 12 (see configure_system_12 )
+ *-----USB_PROD----->[IPA]----
+ * USB2_CONS (MBIM aggregation byte limit)--->
+ *-USB2_PROD (MBIM deaggregation)->[IPA]----USB3_CONS--->
+ *------------------>[IPA]----
+ * USB_CONS (MBIM aggregation time limit)----------->
+ *------------------>[IPA]----
+ * A5_LAN_WAN_CONS (MBIM aggregation no limits)---->
+ *----------------------------------------------------------------------
+ */
+#define CONFIG_12_TO_IPA				"/dev/to_ipa_0"
+#define CONFIG_12_TO_IPA_DEAGG			"/dev/to_ipa_1"
+#define CONFIG_12_FROM_IPA_AGG			"/dev/from_ipa_0"
+#define CONFIG_12_FROM_IPA				"/dev/from_ipa_1"
+#define CONFIG_12_FROM_IPA_AGG_TIME		"/dev/from_ipa_2"
+#define CONFIG_12_FROM_IPA_ZERO_LIMITS	"/dev/from_ipa_3"
+
+/*Configuration 7 (see configure_system_7 )
+ *                  [IPA]----USB2_CONS-->
+ *-----USB_PROD--->[IPA]----USB3_CONS--->
+ *                  [IPA]----Q6_LAN_CONS--->
+ *                  [IPA]----A5 - Exception Pipe--->
+ */
+#define CONFIG_7_FROM_USB1_TO_IPA		"/dev/to_ipa_0"
+#define CONFIG_7_FROM_IPA_TO_A5_EXCEPTION	"/dev/ipa_exception_pipe"
+
+/*----------------------------------------------------------------------
+ *Configuration 17 (see configure_system_17 )
+ *-----USB_PROD----->[IPA]----
+ * USB2_CONS (RNDIS aggregation byte limit)--->
+ * USB2_PROD (RNDIS deaggregation)->[IPA]----USB3_CONS--->
+ *------------------>[IPA]----
+ * USB_CONS (RNDIS aggregation time limit)----------->
+ *------------------>[IPA]----
+ * A5_LAN_WAN_CONS (RNDIS aggregation no limits)---->
+ *----------------------------------------------------------------------
+ */
+#define CONFIG_17_TO_IPA				"/dev/to_ipa_0"
+#define CONFIG_17_TO_IPA_NO_HDR			"/dev/to_ipa_1"
+#define CONFIG_17_TO_IPA_DEAGG			"/dev/to_ipa_2"
+#define CONFIG_17_FROM_IPA_AGG			"/dev/from_ipa_0"
+#define CONFIG_17_FROM_IPA				"/dev/from_ipa_1"
+#define CONFIG_17_FROM_IPA_AGG_TIME		"/dev/from_ipa_2"
+#define CONFIG_17_FROM_IPA_ZERO_LIMITS	"/dev/from_ipa_3"
+
+/*----------------------------------------------------------------------
+ *Configuration 18 (see configure_system_18 )---------------------------
+ *-----USB_PROD----->[IPA]--------------->USB_CONS--------->A5----------
+ *-----USB_PROD2 is a dummy endpoint handle for packet handling between-
+ *-----user space and kernel space in the IPA driver--------------------
+ *----------------------------------------------------------------------
+ */
+#define CONFIG_18_TO_IPA				"/dev/to_ipa_0"
+#define CONFIG_18_DUMMY_ENDPOINT		"/dev/to_ipa_1"
+#define CONFIG_18_FROM_IPA			"/dev/from_ipa_0"
+
+/*----------------------------------------------------------------------
+ *Configuration 19 (see configure_system_19 )
+ *-----USB_PROD--->[IPA DMA]----USB_CONS--->
+ *----------------------------------------------------------------------
+ */
+#define CONFIG_19_FROM_USB_TO_IPA_DMA		"/dev/to_ipa_0"
+#define CONFIG_19_FROM_IPA_TO_USB_DMA		"/dev/from_ipa_0"
+
+enum ipv6_ext_hdr_type {
+	HOP_BY_HOP_OPT	= 0,
+	DEST_OPT	= 60,
+	ROUTING         = 43,
+	FRAGMENT	= 44,
+	AH		= 51,
+	ESP		= 50,
+	DEST_OPT_UL	= 60,
+	Mobility	= 135,
+	NONE		= 59
+};
+/*File that are being used by the test application:*/
+
+#define IPV4_FILE_PATH				"Input/IPV4_3"
+
+/*---------------------------------------------------------------------
+ *XUnit tests results format file name
+ *----------------------------------------------------------------------
+ */
+#define XUNIT_REPORT_PATH_AND_NAME	"junit_result.xml"
+
+#endif /* CONSTANTS_H_ */

+ 105 - 0
kernel-tests/DataPathTestFixture.cpp

@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "DataPathTestFixture.h"
+
+Pipe DataPathTestFixture::m_FromIPAPipe(IPA_CLIENT_TEST_CONS,
+					IPA_TEST_CONFIGURATION_18);
+Pipe DataPathTestFixture::m_ToIpaPipe(IPA_CLIENT_TEST_PROD,
+					IPA_TEST_CONFIGURATION_18);
+Pipe DataPathTestFixture::m_IpaDriverPipe(IPA_CLIENT_TEST2_PROD,
+					IPA_TEST_CONFIGURATION_18);
+
+
+RoutingDriverWrapper DataPathTestFixture::m_Routing;
+Filtering DataPathTestFixture::m_Filtering;
+HeaderInsertion DataPathTestFixture::m_HeaderInsertion;
+
+DataPathTestFixture::DataPathTestFixture()
+{
+	m_testSuiteName.push_back("DataPath");
+	Register(*this);
+}
+
+bool DataPathTestFixture::Setup()
+{
+	bool bRetVal = true;
+
+	/*Set the configuration to support USB->IPA and IPA->USB pipes.*/
+	ConfigureScenario(IPA_TEST_CONFIGURATION_18);
+
+	bRetVal &= m_ToIpaPipe.Init();
+	bRetVal &= m_FromIPAPipe.Init();
+	bRetVal &= m_IpaDriverPipe.Init();
+
+	if (!m_Routing.DeviceNodeIsOpened()) {
+		LOG_MSG_ERROR(
+			"Routing block is not ready for immediate commands!\n");
+		return false;
+	}
+	if (!m_Filtering.DeviceNodeIsOpened()) {
+		LOG_MSG_ERROR(
+			"Filtering block is not ready for immediate commands!\n");
+		return false;
+	}
+	if (!m_HeaderInsertion.DeviceNodeIsOpened())
+	{
+		LOG_MSG_ERROR("Header Insertion block is not ready for immediate commands!\n");
+		return false;
+	}\
+	/*resetting this component will reset both Routing and Filtering tables*/
+	m_HeaderInsertion.Reset();
+
+	return bRetVal;
+}
+
+bool DataPathTestFixture::Teardown()
+{
+	/*The Destroy method will close the inode.*/
+	m_FromIPAPipe.Destroy();
+	m_ToIpaPipe.Destroy();
+	m_IpaDriverPipe.Destroy();
+	return true;
+}
+
+bool DataPathTestFixture::Run()
+{
+	LOG_MSG_DEBUG("Entering Function");
+
+	if (!TestLogic()) {
+		LOG_MSG_ERROR(
+			"Test failed, Input and expected output mismatch.");
+		return false;
+	}
+
+	LOG_MSG_DEBUG("Leaving Function (Returning True)");
+	return true;
+}
+
+

+ 82 - 0
kernel-tests/DataPathTestFixture.h

@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DATAPATHTESTFIXTURE_H_
+#define DATAPATHTESTFIXTURE_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <linux/if_ether.h>
+
+#include "Constants.h"
+#include "Logger.h"
+#include "linux/msm_ipa.h"
+#include "TestsUtils.h"
+#include "TestBase.h"
+#include "Pipe.h"
+#include "RoutingDriverWrapper.h"
+#include "HeaderInsertion.h"
+#include "Filtering.h"
+#include "IPAFilteringTable.h"
+
+class DataPathTestFixture:public TestBase
+{
+public:
+	/*
+	 * This Constructor will register each instance
+	 * that it creates.
+	 */
+	DataPathTestFixture();
+
+	/*
+	 * This method will create and initialize two Pipe object for the USB
+	 * (Ethernet) Pipes, one as input and the other as output.
+	 */
+	virtual bool Setup();
+
+	/*This method will destroy the pipes.*/
+	virtual bool Teardown();
+
+	virtual bool Run();
+
+	virtual bool TestLogic() = 0;
+
+	/*The client type are set from the peripheral perspective*/
+	static Pipe m_FromIPAPipe;
+	static Pipe m_ToIpaPipe;
+	static Pipe m_IpaDriverPipe;
+
+	static RoutingDriverWrapper m_Routing;
+	static Filtering m_Filtering;
+	static HeaderInsertion m_HeaderInsertion;
+};
+#endif /* DATAPATHTESTFIXTURE_H_ */

+ 391 - 0
kernel-tests/DataPathTests.cpp

@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include "hton.h" /* for htonl*/
+#include "DataPathTestFixture.h"
+#include "Constants.h"
+#include "TestsUtils.h"
+#include "linux/msm_ipa.h"
+
+#define PACKET_SIZE ((10)*(4))
+
+class IpaTxDpTest:public DataPathTestFixture {
+
+public:
+	IpaTxDpTest() {
+		m_name = "IpaTxDpTest";
+		m_description = "Sending one SKB via ipa_tx_dp() and checking"
+				"if it was received";
+		m_runInRegression = true;
+	}
+
+	bool TestLogic() {
+		LOG_MSG_DEBUG("Entering %s\n", __func__);
+		int ret;
+		unsigned char *input, *output;
+		char pkt[PACKET_SIZE] = {
+			0x59, 0x61, 0x6e, 0x69,
+			0x76, 0x5f, 0x48 ,0x61,
+			0x73 ,0x62 ,0x61 ,0x6e,
+			0x69 ,0x5f ,0x54 ,0x68,
+			0x65 ,0x5f ,0x47 ,0x72,
+			0x65 ,0x61 ,0x74 ,0x16,
+			0x32 ,0x49 ,0x0c ,0x3f,
+			0x37 ,0x23 ,0x6d ,0x15,
+			0x50 ,0x10 ,0x3f ,0xbd,
+			0xcc ,0xd8 ,0x00, 0x00
+		};
+
+		input = (unsigned char *)malloc(PACKET_SIZE);
+		if(!input) {
+			LOG_MSG_ERROR("Error in allocation\n");
+			goto fail;
+		}
+
+		output = (unsigned char *)malloc(PACKET_SIZE);
+		if(!output) {
+			LOG_MSG_ERROR("Error in allocation\n");
+			free(input);
+			goto fail;
+		}
+
+		memcpy(input, pkt, PACKET_SIZE);
+		LOG_MSG_DEBUG("Sending packet through ipa_tx_dp() in func %s\n", __func__);
+		ret = m_IpaDriverPipe.Send(input, PACKET_SIZE);
+
+		if (ret != PACKET_SIZE) {
+			LOG_MSG_ERROR(
+				"Amount of bits sent are: %d instead of %d\nExiting..\n"
+				, ret
+				, PACKET_SIZE);
+			free(input);
+			free(output);
+			goto fail;
+		}
+
+		ret = m_FromIPAPipe.Receive(output, PACKET_SIZE);
+		if (ret != PACKET_SIZE) {
+			LOG_MSG_ERROR(
+				"Amount of bits sent are: %d instead of %d\nExiting..\n",
+				ret,
+				PACKET_SIZE);
+			free(input);
+			free(output);
+			goto fail;
+		}
+
+		LOG_MSG_INFO("Input buff:\n");
+		print_buff(input, PACKET_SIZE);
+		LOG_MSG_INFO("Output buff:\n");
+		print_buff(output, PACKET_SIZE);
+		if (memcmp(input,output, PACKET_SIZE)) {
+			free(input);
+			free(output);
+			return false;
+		}
+
+		free(input);
+		free(output);
+		return true;
+fail:
+		return false;
+	}
+};
+
+class IpaTxDpMultipleTest:public DataPathTestFixture {
+
+public:
+	IpaTxDpMultipleTest() {
+		m_name = "IpaTxDpMultipleTest";
+		m_description = "Sending multiple SKB via ipa_tx_dp() and checking"
+				"if it was received";
+		m_runInRegression = false;
+	}
+
+	bool TestLogic() {
+		int packet_to_send = 10;
+		int loop_size = 100;
+		int i;
+		int j;
+
+		LOG_MSG_DEBUG("Entering %s\n", __func__);
+		int ret;
+		unsigned char *input, *output;
+		char pkt[PACKET_SIZE] = {
+			0x59, 0x61, 0x6e, 0x69,
+			0x76, 0x5f, 0x48 ,0x61,
+			0x73 ,0x62 ,0x61 ,0x6e,
+			0x69 ,0x5f ,0x54 ,0x68,
+			0x65 ,0x5f ,0x47 ,0x72,
+			0x65 ,0x61 ,0x74 ,0x16,
+			0x32 ,0x49 ,0x0c ,0x3f,
+			0x37 ,0x23 ,0x6d ,0x15,
+			0x50 ,0x10 ,0x3f ,0xbd,
+			0xcc ,0xd8 ,0x00, 0x00
+		};
+
+		input = (unsigned char *)malloc(PACKET_SIZE);
+		if(!input) {
+			LOG_MSG_ERROR("Error in allocation\n");
+			goto fail;
+		}
+
+		output = (unsigned char *)malloc(PACKET_SIZE);
+		if(!output) {
+			LOG_MSG_ERROR("Error in allocation\n");
+			free(input);
+			goto fail;
+		}
+
+		memcpy(input, pkt, PACKET_SIZE);
+		for (i = 0; i < loop_size; i++) {
+			for (j = 0; j < packet_to_send; j++) {
+				input[0] = i;
+				input[1] = j;
+				LOG_MSG_DEBUG("Sending packet through ipa_tx_dp() in func %s\n", __func__);
+				ret = m_IpaDriverPipe.Send(input, PACKET_SIZE);
+				if (ret != PACKET_SIZE) {
+					LOG_MSG_ERROR(
+						"Amount of bits sent are: %d instead of %d\nExiting..\n"
+						, ret
+						, PACKET_SIZE);
+					free(input);
+					free(output);
+					goto fail;
+				}
+			}
+
+			for (j = 0; j < packet_to_send; j++) {
+				ret = m_FromIPAPipe.Receive(output, PACKET_SIZE);
+				if (ret != PACKET_SIZE) {
+					LOG_MSG_ERROR(
+						"Amount of bits sent are: %d instead of %d\nExiting..\n",
+						ret,
+						PACKET_SIZE);
+					free(input);
+					free(output);
+					goto fail;
+				}
+				input[0] = i;
+				input[1] = j;
+				LOG_MSG_INFO("Input buff:\n");
+				print_buff(input, PACKET_SIZE);
+				LOG_MSG_INFO("Output buff:\n");
+				print_buff(output, PACKET_SIZE);
+				if (memcmp(input,output, PACKET_SIZE)) {
+					free(input);
+					free(output);
+					LOG_MSG_ERROR("Failed in buffers comparison");
+					return false;
+				}
+			}
+		}
+
+		free(input);
+		free(output);
+		return true;
+fail:
+		return false;
+	}
+};
+
+class IPAToAppsTest:public DataPathTestFixture {
+
+public:
+	IPAToAppsTest() {
+		m_name = "IPAToApps";
+		m_description = "Sending one SKB via USB_PROD pipe and checking"
+				"if it was received";
+		m_runInRegression = true;
+	}
+
+	bool TestLogic() {
+		int ret;
+		unsigned char *input, *output;
+		unsigned char pkt[PACKET_SIZE] = {
+			0x59, 0x61, 0x6e, 0x69,
+			0x76, 0x5f, 0x48 ,0x61,
+			0x73 ,0x62 ,0x61 ,0x6e,
+			0x69 ,0x5f ,0x54 ,0x68,
+			0x65 ,0x5f ,0x47 ,0x72,
+			0x65 ,0x61 ,0x74 ,0x16,
+			0x32 ,0x49 ,0x0c ,0x3f,
+			0x37 ,0x23 ,0x6d ,0x15,
+			0x50 ,0x10 ,0x3f ,0xbd,
+			0xcc ,0xd8 ,0x00, 0x00
+		};
+
+		input = (unsigned char *)malloc(PACKET_SIZE);
+		if(!input) {
+			LOG_MSG_ERROR("Error in allocation\n");
+			goto fail;
+		}
+		output = (unsigned char *)malloc(PACKET_SIZE);
+		if(!output) {
+			LOG_MSG_ERROR("Error in allocation\n");
+			free(input);
+			goto fail;
+		}
+		memcpy(input, pkt, PACKET_SIZE);
+
+		LOG_MSG_DEBUG("Sending packet through USB_PROD pipe in func %s\n", __func__);
+		ret = m_ToIpaPipe.Send(input, PACKET_SIZE);
+		if (ret != PACKET_SIZE) {
+			LOG_MSG_ERROR(
+				"Amount of bits sent are: %d instead of %d\nExiting..\n",
+				ret,
+				PACKET_SIZE);
+			goto fail;
+		}
+		LOG_MSG_DEBUG("Reading packet through Dummy Endpoint pipe in func %s\n", __func__);
+		ret = m_IpaDriverPipe.Receive(output, PACKET_SIZE);
+		if (ret != 0) {
+			LOG_MSG_ERROR("Failed in reading buffer. %d error", ret);
+			free(input);
+			free(output);
+			goto fail;
+		}
+		LOG_MSG_DEBUG("SKB original packet:\n");
+		print_buff(input, PACKET_SIZE);
+		LOG_MSG_DEBUG("SKB received packet:\n");
+		print_buff(output, PACKET_SIZE);
+		if (memcmp(input,output, PACKET_SIZE)) {
+			free(input);
+			free(output);
+			return false;
+		}
+		free(input);
+		free(output);
+		return true;
+fail:
+		return false;
+	}
+};
+
+class IPAToAppsMultipleTest:public DataPathTestFixture {
+
+public:
+	IPAToAppsMultipleTest() {
+		m_name = "IPAToAppsMultipleTest";
+		m_description = "Sending multiple SKB via USB_PROD pipe and checking"
+				"if they was received";
+		m_runInRegression = false;
+	}
+
+	bool TestLogic() {
+		int packet_to_send = 10;
+		int loop_size = 100;
+		int i;
+		int j;
+		int ret;
+		unsigned char *input, *output;
+		unsigned char pkt[PACKET_SIZE] = {
+			0x59, 0x61, 0x6e, 0x69,
+			0x76, 0x5f, 0x48 ,0x61,
+			0x73 ,0x62 ,0x61 ,0x6e,
+			0x69 ,0x5f ,0x54 ,0x68,
+			0x65 ,0x5f ,0x47 ,0x72,
+			0x65 ,0x61 ,0x74 ,0x16,
+			0x32 ,0x49 ,0x0c ,0x3f,
+			0x37 ,0x23 ,0x6d ,0x15,
+			0x50 ,0x10 ,0x3f ,0xbd,
+			0xcc ,0xd8 ,0x00, 0x00
+		};
+
+		input = (unsigned char *)malloc(PACKET_SIZE);
+		if(!input) {
+			LOG_MSG_ERROR("Error in allocation\n");
+			goto fail;
+		}
+		output = (unsigned char *)malloc(PACKET_SIZE);
+		if(!output) {
+			LOG_MSG_ERROR("Error in allocation\n");
+			free(input);
+			goto fail;
+		}
+		memcpy(input, pkt, PACKET_SIZE);
+		for (i = 0; i < loop_size; i++) {
+			for (j = 0; j < packet_to_send; j++) {
+				input[0] = i;
+				input[1] = j;
+
+				LOG_MSG_DEBUG("Sending packet through USB_PROD pipe in func %s\n", __func__);
+				ret = m_ToIpaPipe.Send(input, PACKET_SIZE);
+				if (ret != PACKET_SIZE) {
+					LOG_MSG_ERROR(
+						"Amount of bits sent are: %d instead of %d\nExiting..\n",
+						ret,
+						PACKET_SIZE);
+					free(input);
+					free(output);
+					goto fail;
+				}
+			}
+
+			for (j = 0; j < packet_to_send; j++) {
+				input[0] = i;
+				input[1] = j;
+				LOG_MSG_DEBUG("Reading packet through Dummy Endpoint pipe in func %s\n", __func__);
+				ret = m_IpaDriverPipe.Receive(output, PACKET_SIZE);
+				if (ret != 0) {
+					LOG_MSG_ERROR("Failed in reading buffer. %d error", ret);
+					free(input);
+					free(output);
+					goto fail;
+				}
+				LOG_MSG_DEBUG("SKB original packet:\n");
+				print_buff(input, PACKET_SIZE);
+				LOG_MSG_DEBUG("SKB received packet:\n");
+				print_buff(output, PACKET_SIZE);
+				if (memcmp(input,output, PACKET_SIZE)) {
+					free(input);
+					free(output);
+					LOG_MSG_ERROR("Failed in buffers comparison");
+					return false;
+				}
+			}
+		}
+		free(input);
+		free(output);
+		return true;
+fail:
+		return false;
+	}
+};
+
+
+static IpaTxDpTest ipaTxDpTest;
+static IpaTxDpMultipleTest ipaTxDpMultipleTest;
+static IPAToAppsTest ipaToApps;
+static IPAToAppsMultipleTest iPAToAppsMultipleTestApps;

+ 472 - 0
kernel-tests/ExceptionTests.cpp

@@ -0,0 +1,472 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "TestsUtils.h"
+#include "RoutingDriverWrapper.h"
+#include "HeaderInsertion.h"
+#include "Filtering.h"
+#include "IPAFilteringTable.h"
+#include <string.h>
+
+using namespace IPA;
+
+class IPAExceptionTestFixture: public TestBase {
+public:
+
+	IPAExceptionTestFixture() :
+			m_uBufferSize(0) {
+		memset(m_aBuffer, 0, sizeof(m_aBuffer));
+		m_testSuiteName.push_back("Exception");
+	}
+
+	virtual bool AddRules() = 0;
+	virtual bool ModifyPackets() = 0;
+	virtual bool TestLogic() = 0;
+
+	bool Setup() {
+
+		ConfigureScenario(PHASE_SEVEN_TEST_CONFIGURATION);
+
+		m_producer.Open(INTERFACE0_TO_IPA_DATA_PATH,
+				INTERFACE0_FROM_IPA_DATA_PATH);
+		m_Consumer1.Open(INTERFACE1_TO_IPA_DATA_PATH,
+				INTERFACE1_FROM_IPA_DATA_PATH);
+		m_Consumer2.Open(INTERFACE2_TO_IPA_DATA_PATH,
+				INTERFACE2_FROM_IPA_DATA_PATH);
+		m_Consumer3.Open(INTERFACE3_TO_IPA_DATA_PATH,
+				INTERFACE3_FROM_IPA_DATA_PATH);
+		m_Exceptions.Open(INTERFACE_TO_IPA_EXCEPTION_PATH,
+				INTERFACE_FROM_IPA_EXCEPTION_PATH);
+
+
+		if (!m_Routing.DeviceNodeIsOpened()) {
+			LOG_MSG_ERROR(
+					"Routing block is not ready for immediate commands!\n");
+			return false;
+		}
+		if (!m_Filtering.DeviceNodeIsOpened()) {
+			LOG_MSG_ERROR(
+					"Filtering block is not ready for immediate commands!\n");
+			return false;
+		}
+		if (!m_HeaderInsertion.DeviceNodeIsOpened())
+		{
+			LOG_MSG_ERROR("Header Insertion block is not ready for immediate commands!\n");
+			return false;
+		}
+		m_HeaderInsertion.Reset();
+
+		return true;
+	} // Setup()
+
+	bool Run() {
+		m_uBufferSize = BUFF_MAX_SIZE;
+		LOG_MSG_STACK("Entering Function");
+
+		// Configure the system by adding Routing / Filtering / HDR
+		if (!AddRules()) {
+			LOG_MSG_ERROR("Failed adding Routing / Filtering / HDR.");
+			return false;
+		}
+		// Load input data (IP packet) from file
+		if (!LoadDefaultPacket(m_eIP, m_aBuffer, m_uBufferSize)) {
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		if (!ModifyPackets()) {
+			LOG_MSG_ERROR("Failed to modify packets.");
+			return false;
+		}
+		if (!TestLogic()) {
+			LOG_MSG_ERROR("Test failed, Input and expected output mismatch.");
+			return false;
+		}
+		LOG_MSG_STACK("Leaving Function (Returning True)");
+		return true;
+	} // Run()
+
+	bool Teardown() {
+		m_producer.Close();
+		m_Consumer1.Close();
+		m_Consumer2.Close();
+		m_Consumer3.Close();
+		m_Exceptions.Close();
+		return true;
+	} // Teardown()
+
+	~IPAExceptionTestFixture() {
+	}
+
+	static RoutingDriverWrapper m_Routing;
+	static Filtering m_Filtering;
+	static HeaderInsertion m_HeaderInsertion;
+	InterfaceAbstraction m_producer;
+	InterfaceAbstraction m_Consumer1;
+	InterfaceAbstraction m_Consumer2;
+	InterfaceAbstraction m_Consumer3;
+	InterfaceAbstraction m_Exceptions;
+
+protected:
+	static const size_t BUFF_MAX_SIZE = 1024;
+	static const uint8_t MAX_HEADER_SIZE = 64; // 64Bytes - Max Header Length
+	enum ipa_ip_type m_eIP;
+	uint8_t m_aBuffer[BUFF_MAX_SIZE]; // Input file \ IP packet
+	size_t m_uBufferSize;
+
+};
+RoutingDriverWrapper IPAExceptionTestFixture::m_Routing;
+Filtering IPAExceptionTestFixture::m_Filtering;
+HeaderInsertion IPAExceptionTestFixture::m_HeaderInsertion;
+
+//----------------------------------------------------------------------------------------------------------------------------------------/
+// Test001: Test that when a packet with (IPVer != 4) && (IPVer Ver != 6) , an exception packet is created and received & exception_pipe  /
+//----------------------------------------------------------------------------------------------------------------------------------------/
+class IPAExceptionPacketTest001: public IPAExceptionTestFixture {
+public:
+	IPAExceptionPacketTest001() {
+		m_name = "IPAExceptionPacketTest001";
+		m_description = "\
+			IPA Exception Test 001 - Test that when a packet with (IPVer != 4) && (IPVer Ver != 6) , an exception packet is created and received & exception_pipe \
+			Test Generates send NUM_OF_EXCEPTION_PKTS packets with IP Version changing from  0 to 9.\
+			First IP Version == 4, hence it is not considered as exception (same goes for IP Ver == 6) \
+			";
+		m_eIP = IPA_IP_v4;
+		Register(*this);
+	}
+
+	virtual bool AddRules() {
+		// Clear All Rules
+		bool bRetVal = true;
+		LOG_MSG_STACK("Entering Function");
+
+		const char bypass0[20] = "Bypass0";
+		struct ipa_ioc_get_rt_tbl sRoutingTable;
+		IPAFilteringTable cFilterTable;
+		struct ipa_flt_rule_add sFilterRuleEntry;
+		uint32_t nRTTableHdl=0;
+		memset(&sRoutingTable, 0, sizeof(sRoutingTable));
+
+		LOG_MSG_STACK("Entering Function");
+		if (!CreateBypassRoutingTable(&m_Routing, m_eIP, bypass0, IPA_CLIENT_TEST2_CONS,
+				0,&nRTTableHdl)) {
+			LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+		}
+		LOG_MSG_INFO("CreateBypassRoutingTable completed successfully");
+		sRoutingTable.ip = m_eIP;
+		strlcpy(sRoutingTable.name, bypass0, sizeof(sRoutingTable.name));
+		if (!m_Routing.GetRoutingTable(&sRoutingTable)) {
+			LOG_MSG_ERROR(
+					"m_routing.GetRoutingTable(&sRoutingTable=0x%p) Failed.", &sRoutingTable);
+			bRetVal = false;
+			goto bail;
+		}
+		// Creating Filtering Rules
+		cFilterTable.Init(m_eIP,IPA_CLIENT_TEST_PROD,true,1);
+		LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+		// Configuring Filtering Rule No.1
+		cFilterTable.GeneratePresetRule(0,sFilterRuleEntry);
+		sFilterRuleEntry.at_rear = true;
+		sFilterRuleEntry.flt_rule_hdl = -1; // return Value
+		sFilterRuleEntry.status = -1; // return value
+		sFilterRuleEntry.rule.action = IPA_PASS_TO_ROUTING;
+		sFilterRuleEntry.rule.rt_tbl_hdl = nRTTableHdl;
+		if (
+				((uint8_t)-1 == cFilterTable.AddRuleToTable(sFilterRuleEntry)) ||
+				!m_Filtering.AddFilteringRule(cFilterTable.GetFilteringTable())
+				)
+		{
+			LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+			bRetVal = false;
+			goto bail;
+		} else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable.ReadRuleFromTable(0)->status);
+		}
+
+	bail:
+		LOG_MSG_STACK(
+				"Leaving Function (Returning %s)", bRetVal?"True":"False");
+		return bRetVal;
+	} // AddRules()
+
+	virtual bool ModifyPackets() {
+		m_eIP = IPA_IP_v6;
+
+		AddRules(); // Need to add Routing / Filtering rules for IPv6 as well.
+		return true;
+	} // ModifyPacktes ()
+
+	virtual bool TestLogic() {
+		int i = 0, nIPVer = 0;;
+		memset(m_aExpectedBuffer, 0, sizeof(m_aExpectedBuffer));
+		m_aExpectedBuffer[2] = 0x0b;
+		m_aExpectedBuffer[3] = 0x80;
+
+		memcpy(m_aExpectedBuffer+8, m_aBuffer, m_uBufferSize);
+		m_aExpectedBufSize = m_uBufferSize+8;
+
+		for (i=0;i<NUM_OF_EXCEPTION_PKTS;i++)
+		{
+		LOG_MSG_INFO("Packet %d\n",i);
+			nIPVer = i+4 % 10;
+			m_aBuffer[0] = (m_aBuffer[0] & 0x0F)+0x10*nIPVer;// Change to Invalid IP version
+			m_aExpectedBuffer[8] = (m_aExpectedBuffer[8] & 0x0F)+0x10*nIPVer;
+			if (4 == nIPVer || 6 == nIPVer)
+			{
+				if (!SendReceiveAndCompare(&m_producer, m_aBuffer, m_uBufferSize,
+						&m_Consumer1, m_aExpectedBuffer+8, m_aExpectedBufSize-8))
+				{
+					LOG_MSG_ERROR("SendReceiveAndCompare failed. IPVer = %d",nIPVer);
+					return false;
+				}
+			} else
+			{
+				if (!SendReceiveAndCompare(&m_producer, m_aBuffer, m_uBufferSize,
+						&m_Exceptions, m_aExpectedBuffer, m_aExpectedBufSize))
+				{
+				LOG_MSG_ERROR("SendReceiveAndCompare failed. IPVer = %d",nIPVer);
+				return false;
+				}
+			}
+		}
+		return true;
+	}
+private:
+	static const int NUM_OF_EXCEPTION_PKTS = 9;
+	uint8_t m_aExpectedBuffer[BUFF_MAX_SIZE];
+	size_t m_aExpectedBufSize;
+};
+
+//------------------------------------------------------------------------------------------------------------------------------------------/
+// Test003: Test that when Filtering Routes the Packet to the Exception Pipe, an exception packet is created and received & exception_pipe  /
+//------------------------------------------------------------------------------------------------------------------------------------------/
+class IPAExceptionPacketTest003: public IPAExceptionTestFixture {
+public:
+	IPAExceptionPacketTest003() {
+		m_name = "IPAExceptionPacketTest003";
+		m_description = "\
+			IPA Exception Test 003 - Test that when Filtering Routes the Packet to the Exception Pipe, an exception packet is created and received & exception_pipe \
+			Test Generates a Filtering Table that routes all packets to the Exception Pipe. \
+			and verify that the packet is recieved @ the Exception Pipe. \
+			";
+		m_eIP = IPA_IP_v4;
+		Register(*this);
+	}
+
+	virtual bool AddRules() {
+		// Clear All Rules
+		bool bRetVal = true;
+		LOG_MSG_STACK("Entering Function");
+
+		const char bypass0[20] = "Bypass0";
+		struct ipa_ioc_get_rt_tbl sRoutingTable;
+		IPAFilteringTable cFilterTable;
+		struct ipa_flt_rule_add sFilterRuleEntry;
+		uint32_t nRTTableHdl=0;
+		memset(&sRoutingTable, 0, sizeof(sRoutingTable));
+
+		LOG_MSG_STACK("Entering Function");
+		if (!CreateBypassRoutingTable(&m_Routing, m_eIP, bypass0, IPA_CLIENT_TEST2_CONS,
+				0,&nRTTableHdl)) {
+			LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+		}
+		LOG_MSG_INFO("CreateBypassRoutingTable completed successfully");
+		sRoutingTable.ip = m_eIP;
+		strlcpy(sRoutingTable.name, bypass0, sizeof(sRoutingTable.name));
+		if (!m_Routing.GetRoutingTable(&sRoutingTable)) {
+			LOG_MSG_ERROR(
+					"m_routing.GetRoutingTable(&sRoutingTable=0x%p) Failed.", &sRoutingTable);
+			bRetVal = false;
+			goto bail;
+		}
+		// Creating Filtering Rules
+		cFilterTable.Init(m_eIP,IPA_CLIENT_TEST_PROD,true,1);
+		LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+		// Configuring Filtering Rule No.1
+		cFilterTable.GeneratePresetRule(0,sFilterRuleEntry);
+		sFilterRuleEntry.at_rear = true;
+		sFilterRuleEntry.flt_rule_hdl = -1; // return Value
+		sFilterRuleEntry.status = -1; // return value
+		sFilterRuleEntry.rule.action = IPA_PASS_TO_EXCEPTION;
+		sFilterRuleEntry.rule.rt_tbl_hdl = nRTTableHdl;
+		if (
+				((uint8_t)-1 == cFilterTable.AddRuleToTable(sFilterRuleEntry)) ||
+				!m_Filtering.AddFilteringRule(cFilterTable.GetFilteringTable())
+				)
+		{
+			LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+			bRetVal = false;
+			goto bail;
+		} else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable.ReadRuleFromTable(0)->status);
+		}
+
+	bail:
+		LOG_MSG_STACK(
+				"Leaving Function (Returning %s)", bRetVal?"True":"False");
+		return bRetVal;
+	} // AddRules()
+
+	virtual bool ModifyPackets() {
+		return true;
+	} // ModifyPacktes ()
+
+	virtual bool TestLogic() {
+		memset(m_aExpectedBuffer, 0, sizeof(m_aExpectedBuffer));
+		m_aExpectedBuffer[2] = 0x0b;
+		m_aExpectedBuffer[3] = 0x20;
+
+		memcpy(m_aExpectedBuffer+8, m_aBuffer, m_uBufferSize);
+		m_aExpectedBufSize = m_uBufferSize+8;
+
+		if (!SendReceiveAndCompare(&m_producer, m_aBuffer, m_uBufferSize,
+			&m_Exceptions, m_aExpectedBuffer, m_aExpectedBufSize))
+			{
+				LOG_MSG_ERROR("SendReceiveAndCompare failed.");
+				return false;
+			}
+		return true;
+		}
+private:
+	uint8_t m_aExpectedBuffer[BUFF_MAX_SIZE];
+	size_t m_aExpectedBufSize;
+};
+
+//-----------------------------------------------------------------------------------------------------------------------------------------/
+// Test006: Test that when a packet with Internet Header Length < 5 Arrives, an exception packet is created and received & exception_pipe  /
+//-----------------------------------------------------------------------------------------------------------------------------------------/
+class IPAExceptionPacketTest006: public IPAExceptionTestFixture {
+public:
+	IPAExceptionPacketTest006() {
+		m_name = "IPAExceptionPacketTest006"
+		m_description = "\
+			IPA Exception Test 006 - Test that when a packet with Internet Header Length < 5 Arrives, an exception packet is created and received & exception_pipe \
+			Test Generates a Packet with Internet Header Length (IHL == 4). \
+			and verifies that the packet is recieved @ the Exception Pipe. \
+			";
+		m_eIP = IPA_IP_v4;
+		Register(*this);
+	}
+
+	virtual bool AddRules() {
+		// Clear All Rules
+		bool bRetVal = true;
+		LOG_MSG_STACK("Entering Function");
+
+		const char bypass0[20] = "Bypass0";
+		struct ipa_ioc_get_rt_tbl sRoutingTable;
+		IPAFilteringTable cFilterTable;
+		struct ipa_flt_rule_add sFilterRuleEntry;
+		uint32_t nRTTableHdl=0;
+		memset(&sRoutingTable, 0, sizeof(sRoutingTable));
+
+		LOG_MSG_STACK("Entering Function");
+		if (!CreateBypassRoutingTable(&m_Routing, m_eIP, bypass0, IPA_CLIENT_TEST2_CONS,
+				0,&nRTTableHdl)) {
+			LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+		}
+		LOG_MSG_INFO("CreateBypassRoutingTable completed successfully");
+		sRoutingTable.ip = m_eIP;
+		strlcpy(sRoutingTable.name, bypass0, sizeof(sRoutingTable.name));
+		if (!m_Routing.GetRoutingTable(&sRoutingTable)) {
+			LOG_MSG_ERROR(
+					"m_routing.GetRoutingTable(&sRoutingTable=0x%p) Failed.", &sRoutingTable);
+			bRetVal = false;
+			goto bail;
+		}
+		// Creating Filtering Rules
+		cFilterTable.Init(m_eIP,IPA_CLIENT_TEST_PROD,true,1);
+		LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+		// Configuring Filtering Rule No.1
+		cFilterTable.GeneratePresetRule(0,sFilterRuleEntry);
+		sFilterRuleEntry.at_rear = true;
+		sFilterRuleEntry.flt_rule_hdl = -1; // return Value
+		sFilterRuleEntry.status = -1; // return value
+		sFilterRuleEntry.rule.action = IPA_PASS_TO_ROUTING;
+		sFilterRuleEntry.rule.rt_tbl_hdl = nRTTableHdl;
+		if (
+				((uint8_t)-1 == cFilterTable.AddRuleToTable(sFilterRuleEntry)) ||
+				!m_Filtering.AddFilteringRule(cFilterTable.GetFilteringTable())
+				)
+		{
+			LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+			bRetVal = false;
+			goto bail;
+		} else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable.ReadRuleFromTable(0)->status);
+		}
+
+	bail:
+		LOG_MSG_STACK(
+				"Leaving Function (Returning %s)", bRetVal?"True":"False");
+		return bRetVal;
+	} // AddRules()
+
+	virtual bool ModifyPackets() {
+		m_aBuffer[0] =(m_aBuffer[0] & 0xF0)+0x04;// Change the IHL to 4
+		return true;
+	} // ModifyPacktes ()
+
+	virtual bool TestLogic() {
+		memset(m_aExpectedBuffer, 0, sizeof(m_aExpectedBuffer));
+		m_aExpectedBuffer[2] = 0x0b;
+		m_aExpectedBuffer[3] = 0x04;
+
+		memcpy(m_aExpectedBuffer+8, m_aBuffer, m_uBufferSize);
+		m_aExpectedBufSize = m_uBufferSize+8;
+
+		if (!SendReceiveAndCompare(&m_producer, m_aBuffer, m_uBufferSize,
+			&m_Exceptions, m_aExpectedBuffer, m_aExpectedBufSize))
+			{
+				LOG_MSG_ERROR("SendReceiveAndCompare failed.");
+				return false;
+			}
+		return true;
+		}
+private:
+	uint8_t m_aExpectedBuffer[BUFF_MAX_SIZE];
+	size_t m_aExpectedBufSize;
+};
+
+static IPAExceptionPacketTest001 ipaExceptionPacketTest001;
+static IPAExceptionPacketTest002 ipaExceptionPacketTest002;
+static IPAExceptionPacketTest003 ipaExceptionPacketTest003;
+static IPAExceptionPacketTest006 ipaExceptionPacketTest006;
+

+ 57 - 0
kernel-tests/ExceptionsTestFixture.cpp

@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "RoutingDriverWrapper.h"
+#include "HeaderInsertion.h"
+#include "Filtering.h"
+#include "IPAFilteringTable.h"
+#include "TestsUtils.h"
+#include <string.h>
+#include "ExceptionsTestFixture.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+Pipe ExceptionsTestFixture::m_USB1ToIpaPipe(IPA_CLIENT_TEST_PROD, IPA_TEST_CONFIFURATION_7);
+Pipe ExceptionsTestFixture::m_IpaToA5ExceptionPipe(IPA_TEST_CONFIFURATION_7);//Exception pipe
+
+///////////////////////////////////////////////////////////////////////////////
+
+ExceptionsTestFixture::ExceptionsTestFixture(){
+	Register(*this);
+	m_testSuiteName.push_back("Exceptions");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////                                 EOF                             ///////
+///////////////////////////////////////////////////////////////////////////////
+

+ 54 - 0
kernel-tests/ExceptionsTestFixture.h

@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "Routing.h"
+#include "HeaderInsertion.h"
+#include "Filtering.h"
+#include "IPAFilteringTable.h"
+#include "TestsUtils.h"
+#include "Pipe.h"
+#include <string.h>
+
+#ifndef _EXCEPTION_TESTS_FIXTURE_
+#define _EXCEPTION_TESTS_FIXTURE_
+
+class ExceptionsTestFixture:public TestBase {
+public:
+	/*This Constructor will register the
+	 *exception tests and set the suit name
+	 */
+	ExceptionsTestFixture();
+protected:
+	static Pipe m_USB1ToIpaPipe;
+	/*from the test application into the IPA(DMUX header)*/
+	static Pipe m_IpaToA5ExceptionPipe;
+	/*from the IPA back to the test application(Exception pipe)*/
+};
+
+#endif

+ 264 - 0
kernel-tests/ExceptionsTests.cpp

@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "RoutingDriverWrapper.h"
+#include "HeaderInsertion.h"
+#include "Filtering.h"
+#include "IPAFilteringTable.h"
+#include "TestsUtils.h"
+#include "ExceptionsTestFixture.h"
+#include "IPv4Packet.h"
+#include <string.h>
+
+#define MAX_SENT_BUFFER_SIZE 1500
+#define MAX_RECEIVE_BUFFER_SIZE 1500
+#define VALIDATE_WITH_MSG_AND_RETVAL(bRetVal,msg) \
+	if (false == bRetVal){  \
+		LOG_MSG_ERROR(msg); \
+		return false;	    \
+	}
+
+using namespace IPA;
+
+///////////////////////////////////////////////////////////////////////////////
+
+class ExceptionsTestNonIpPacket: public ExceptionsTestFixture {
+public:
+	//The packet size to be sent
+	size_t m_nPacketSize;
+	//A buffer to hold the non-IP(V4/V6) packet
+	Byte *m_pSendBuffer;
+
+	///////////////////////////////////////////////////////////////////////////
+
+	//Set the tests name and description
+	ExceptionsTestNonIpPacket() :
+			m_nPacketSize(0), m_pSendBuffer(NULL) {
+		m_name = "ExceptionsTestNonIpPacket";
+		m_description =
+				"Create a non-IP packet(version!=4 && version !=6) and \
+				expect exception from Filter block";
+	}
+
+	///////////////////////////////////////////////////////////////////////////
+
+	virtual bool Run() {
+		bool bRetVal = true;
+		Byte *pReceiveBuffer = new Byte[MAX_RECEIVE_BUFFER_SIZE];
+		//Send the non-IPV4/IPV6 packet to the IPA
+		LOG_MSG_DEBUG("Send the non-IPV4/IPV6 packet to the IPA");
+		size_t nBytesSent = m_USB1ToIpaPipe.Send(m_pSendBuffer, m_nPacketSize);
+		if (nBytesSent != m_nPacketSize) {
+			LOG_MSG_ERROR("Not all data was sent into the IPA");
+			return false;
+		}
+
+		//Read from the exception pipe(from IPA to A5) - try to read as much as we can
+		size_t nBytesRead = m_IpaToA5ExceptionPipe.Receive(pReceiveBuffer,
+				MAX_RECEIVE_BUFFER_SIZE);
+		if (nBytesRead != nBytesSent) {
+			LOG_MSG_ERROR("Not all data was read:");
+			print_buff(pReceiveBuffer, nBytesRead);
+			return false;
+		}
+
+		//check the exception packet against the one that we sent
+		bRetVal = !memcmp(m_pSendBuffer, pReceiveBuffer, nBytesSent);
+		if (false == bRetVal) {
+			LOG_MSG_ERROR("Received packet is not equal, Received:");
+			print_buff(pReceiveBuffer, nBytesRead);
+			LOG_MSG_ERROR("Received packet is not equal, Sent:");
+			print_buff(m_pSendBuffer, m_nPacketSize);
+			return false;
+		}
+		return true;
+	}
+
+	///////////////////////////////////////////////////////////////////////////
+
+	//build the non-IP packet
+	virtual bool Setup() {
+		bool bRetVal = true;
+		m_pSendBuffer = new Byte[MAX_SENT_BUFFER_SIZE];
+		//Load some default IPV4 packet and save its size
+		m_nPacketSize = MAX_SENT_BUFFER_SIZE; //This parameter is In/Out
+		bRetVal = LoadDefaultPacket(IPA_IP_v4, m_pSendBuffer, m_nPacketSize);
+		VALIDATE_WITH_MSG_AND_RETVAL(bRetVal, "Load failed");
+		//Set the version field to non-IPV4/IPV6(version = 5)
+		m_pSendBuffer[0] &= 0x0F;
+		m_pSendBuffer[0] |= 0x50;
+
+		//initialize Pipes
+		bRetVal = m_USB1ToIpaPipe.Init();
+		VALIDATE_WITH_MSG_AND_RETVAL(bRetVal, "Pipe Initialization failed");
+		bRetVal = m_IpaToA5ExceptionPipe.Init();
+		VALIDATE_WITH_MSG_AND_RETVAL(bRetVal, "Pipe Initialization failed");
+		return true;
+	}
+
+	///////////////////////////////////////////////////////////////////////////
+
+	virtual bool Teardown() {
+		bool bRetVal = true;
+		delete[] m_pSendBuffer;
+		m_USB1ToIpaPipe.Destroy();
+		m_IpaToA5ExceptionPipe.Destroy();
+		return bRetVal;
+	}
+
+	///////////////////////////////////////////////////////////////////////////
+
+};
+//ExceptionTestNoneIpPacket
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+
+class ExceptionsTestFragmentedException: public ExceptionsTestFixture {
+public:
+	//The packet size to be sent
+	size_t m_nPacketSize;
+	//A buffer to hold the non-IP(V4/V6) packet
+	Byte *m_pSendBuffer;
+	Byte *m_pReceiveBuffer;
+
+	///////////////////////////////////////////////////////////////////////////
+
+	//Set the tests name and description
+	ExceptionsTestFragmentedException():m_nPacketSize(0), m_pSendBuffer(NULL),
+			m_pReceiveBuffer(NULL){
+		m_name = "ExceptionsTestFragmentedException";
+		m_description =
+				"Send IP packet with MF set, create global Filter rule \
+				that will hit it as Exception";
+	}
+
+	///////////////////////////////////////////////////////////////////////////
+
+	virtual bool Run() {
+		bool bRetVal = true;
+		//configuring the Filter block to catch the fragmented packet:
+		ConfigureFilterGlobalRuleForMF();
+		//Send the non-IPV4/IPV6 packet to the IPA
+		LOG_MSG_DEBUG("Send the IP packet with the MF bit set(size = %d)", m_nPacketSize);
+		size_t nBytesSent = m_USB1ToIpaPipe.Send(m_pSendBuffer, m_nPacketSize);
+		if (nBytesSent != m_nPacketSize) {
+			LOG_MSG_ERROR("Not all data was sent into the IPA(only %d)", nBytesSent);
+			return false;
+		}
+		//Read from the exception pipe(from IPA to A5) - try to read as much as we can
+		size_t nBytesRead = m_IpaToA5ExceptionPipe.Receive(m_pReceiveBuffer,
+				MAX_RECEIVE_BUFFER_SIZE);
+		if (nBytesRead != nBytesSent) {
+			LOG_MSG_ERROR("Not all data was read:");
+			print_buff(m_pReceiveBuffer, nBytesRead);
+			return false;
+		}
+		//check the exception packet against the one that we sent
+		bRetVal = !memcmp(m_pSendBuffer, m_pReceiveBuffer, nBytesSent);
+		if (false == bRetVal) {
+			LOG_MSG_ERROR("Received packet is not equal, Received:");
+			print_buff(m_pReceiveBuffer, nBytesRead);
+			LOG_MSG_ERROR("Received packet is not equal, Sent:");
+			print_buff(m_pSendBuffer, m_nPacketSize);
+			return false;
+		}
+		return true;
+	}
+
+	///////////////////////////////////////////////////////////////////////////
+
+	//build the non-IP packet
+	virtual bool Setup() {
+		bool bRetVal = true;
+		m_pReceiveBuffer = new Byte[MAX_RECEIVE_BUFFER_SIZE];
+		m_pSendBuffer = new Byte[MAX_RECEIVE_BUFFER_SIZE];
+		//Load some default TCP packet
+		TCPPacket tcpPacket;
+		//Set the MF bit
+		tcpPacket.SetMF(true);
+		//copy the packet to the send buffer
+		m_nPacketSize = tcpPacket.GetSize();
+		tcpPacket.ToNetworkByteStream(m_pSendBuffer);
+		//initialize Pipes
+		bRetVal = m_USB1ToIpaPipe.Init();
+		VALIDATE_WITH_MSG_AND_RETVAL(bRetVal, "Pipe Initialization failed");
+		bRetVal = m_IpaToA5ExceptionPipe.Init();
+		VALIDATE_WITH_MSG_AND_RETVAL(bRetVal, "Pipe Initialization failed");
+		return true;
+	}
+
+	///////////////////////////////////////////////////////////////////////////
+
+	virtual bool Teardown() {
+		bool bRetVal = true;
+		delete[] m_pSendBuffer;
+		m_USB1ToIpaPipe.Destroy();
+		m_IpaToA5ExceptionPipe.Destroy();
+		return bRetVal;
+	}
+
+
+
+	///////////////////////////////////////////////////////////////////////////
+
+	void ConfigureFilterGlobalRuleForMF(){
+		//struct ipa_ioc_add_flt_rule *pRuleTable;
+		//Allocate memory for a table with one rule.
+
+		//Instruct the Driver to write this table(with its one rule) to the HW
+
+		//Continue from here - build the rule to catch the fragmented packet
+	}
+
+	///////////////////////////////////////////////////////////////////////////
+
+
+};
+//ExceptionsTestFragmentedException
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+class ExceptionsTestNonTCPUDP: public ExceptionsTestFixture {
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//Classes instances:
+static ExceptionsTestNonIpPacket exceptionsTestNonIpPacket;
+static ExceptionsTestFragmentedException exceptionsTestFragmentedException;
+
+///////////////////////////////////////////////////////////////////////////////
+//////////////                         EOF                             ////////
+///////////////////////////////////////////////////////////////////////////////

+ 127 - 0
kernel-tests/Filtering.cpp

@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "Filtering.h"
+
+const char* Filtering::DEVICE_NAME = "/dev/ipa";
+
+Filtering::Filtering()
+{
+	fd = open(DEVICE_NAME, O_RDWR);
+	if (0 == fd) {
+		printf("Failed opening %s.\n", DEVICE_NAME);
+	}
+}
+
+Filtering::~Filtering()
+{
+	close(fd);
+}
+
+bool Filtering::DeviceNodeIsOpened()
+{
+	return fd;
+}
+
+bool Filtering::AddFilteringRule(struct ipa_ioc_add_flt_rule const * ruleTable)
+{
+	int retval = 0;
+
+	retval = ioctl(fd, IPA_IOC_ADD_FLT_RULE, ruleTable);
+	if (retval) {
+		printf("%s(), failed adding Filtering rule table %p\n", __FUNCTION__, ruleTable);
+		return false;
+	}
+
+	printf("%s(), Added Filtering rule to table %p\n", __FUNCTION__, ruleTable);
+	return true;
+}
+
+bool Filtering::AddFilteringRule(struct ipa_ioc_add_flt_rule_v2 const * ruleTable)
+{
+	int retval = 0;
+
+	retval = ioctl(fd, IPA_IOC_ADD_FLT_RULE_V2, ruleTable);
+	if (retval) {
+		printf("%s(), failed adding Filtering rule table %p\n", __FUNCTION__, ruleTable);
+		return false;
+	}
+
+	printf("%s(), Added Filtering rule to table %p\n", __FUNCTION__, ruleTable);
+	return true;
+}
+
+bool Filtering::DeleteFilteringRule(struct ipa_ioc_del_flt_rule *ruleTable)
+{
+	int retval = 0;
+
+	retval = ioctl(fd, IPA_IOC_DEL_FLT_RULE, ruleTable);
+	if (retval) {
+		printf("%s(), failed deleting Filtering rule in table %p\n", __FUNCTION__, ruleTable);
+		return false;
+	}
+
+	printf("%s(), Deleted Filtering rule in table %p\n", __FUNCTION__, ruleTable);
+	return true;
+}
+
+bool Filtering::Commit(enum ipa_ip_type ip)
+{
+	int retval = 0;
+
+	retval = ioctl(fd, IPA_IOC_COMMIT_FLT, ip);
+	if (retval) {
+		printf("%s(), failed committing Filtering rules.\n", __FUNCTION__);
+		return false;
+	}
+
+	printf("%s(), Committed Filtering rules to IPA HW.\n", __FUNCTION__);
+	return true;
+}
+
+bool Filtering::Reset(enum ipa_ip_type ip)
+{
+	int retval = 0;
+
+	retval = ioctl(fd, IPA_IOC_RESET_FLT, ip);
+	retval |= ioctl(fd, IPA_IOC_COMMIT_FLT, ip);
+	if (retval) {
+		printf("%s(), failed resetting Filtering block.\n", __FUNCTION__);
+		return false;
+	}
+
+	printf("%s(), Reset command issued to IPA Filtering block.\n", __FUNCTION__);
+	return true;
+}
+

+ 54 - 0
kernel-tests/Filtering.h

@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FILTERING_H_
+#define FILTERING_H_
+
+#include <stdint.h>
+#include "linux/msm_ipa.h"
+
+class Filtering
+{
+public:
+	Filtering();
+	~Filtering();
+	bool AddFilteringRule(struct ipa_ioc_add_flt_rule const *ruleTable);
+	bool AddFilteringRule(ipa_ioc_add_flt_rule_v2 const *ruleTable);
+	bool DeleteFilteringRule(struct ipa_ioc_del_flt_rule *ruleTable);
+	bool Commit(enum ipa_ip_type ip);
+	bool Reset(enum ipa_ip_type ip);
+	bool DeviceNodeIsOpened();
+
+private:
+	static const char *DEVICE_NAME;
+	int fd; /*File descriptor of the IPA device node /dev/ipa*/
+};
+
+#endif
+

+ 513 - 0
kernel-tests/FilteringEthernetBridgingTestFixture.cpp

@@ -0,0 +1,513 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FilteringEthernetBridgingTestFixture.h"
+
+IpaFilteringEthernetBridgingTestFixture::IpaFilteringEthernetBridgingTestFixture():
+	m_sendSize1 (m_BUFF_MAX_SIZE),
+	m_sendSize2 (m_BUFF_MAX_SIZE),
+	m_sendSize3 (m_BUFF_MAX_SIZE),
+	m_IpaIPType(IPA_IP_v4)
+{
+	memset(m_sendBuffer1, 0, sizeof(m_sendBuffer1));
+	memset(m_sendBuffer2, 0, sizeof(m_sendBuffer2));
+	memset(m_sendBuffer3, 0, sizeof(m_sendBuffer3));
+	m_testSuiteName.push_back("FilteringEth");
+}
+
+bool IpaFilteringEthernetBridgingTestFixture::Setup()
+{
+	ConfigureScenario(PHASE_TWO_TEST_CONFIGURATION);
+
+	m_producer.Open(INTERFACE0_TO_IPA_DATA_PATH, INTERFACE0_FROM_IPA_DATA_PATH);
+	m_producer2.Open(INTERFACE4_TO_IPA_DATA_PATH, INTERFACE4_FROM_IPA_DATA_PATH);
+
+	m_consumer.Open(INTERFACE1_TO_IPA_DATA_PATH, INTERFACE1_FROM_IPA_DATA_PATH);
+	m_consumer2.Open(INTERFACE2_TO_IPA_DATA_PATH, INTERFACE2_FROM_IPA_DATA_PATH);
+	m_defaultConsumer.Open(INTERFACE3_TO_IPA_DATA_PATH, INTERFACE3_FROM_IPA_DATA_PATH);
+
+	if (!m_routing.DeviceNodeIsOpened())
+	{
+		LOG_MSG_ERROR("Routing block is not ready for immediate commands!\n");
+		return false;
+	}
+
+	if (!m_filtering.DeviceNodeIsOpened())
+	{
+		LOG_MSG_ERROR("Filtering block is not ready for immediate commands!\n");
+		return false;
+	}
+	m_routing.Reset(IPA_IP_v4);
+	m_routing.Reset(IPA_IP_v6);
+	return true;
+} // Setup()
+
+bool IpaFilteringEthernetBridgingTestFixture::Teardown()
+{
+	m_producer.Close();
+	m_producer2.Close();
+	m_consumer.Close();
+	m_consumer2.Close();
+	m_defaultConsumer.Close();
+	return true;
+} // Teardown()
+
+bool IpaFilteringEthernetBridgingTestFixture::LoadFiles(enum ipa_ip_type ip)
+{
+	if (!LoadDefaultEth2Packet(ip, m_sendBuffer1, m_sendSize1)) {
+		LOG_MSG_ERROR("Failed default Packet\n");
+		return false;
+	}
+	LOG_MSG_DEBUG ("Loaded %zu Bytes to Buffer 1\n",m_sendSize1);
+
+	if (!LoadDefaultEth2Packet(ip, m_sendBuffer2, m_sendSize2)) {
+		LOG_MSG_ERROR("Failed default Packet\n");
+		return false;
+	}
+	LOG_MSG_DEBUG ("Loaded %zu Bytes to Buffer 2\n",m_sendSize2);
+
+	if (!LoadDefaultEth2Packet(ip, m_sendBuffer3, m_sendSize3)) {
+		LOG_MSG_ERROR("Failed default Packet\n");
+		return false;
+	}
+	LOG_MSG_DEBUG ("Loaded %zu Bytes to Buffer 3\n",m_sendSize3);
+
+	return true;
+}
+
+bool IpaFilteringEthernetBridgingTestFixture::ReceivePacketsAndCompare()
+{
+	size_t receivedSize = 0;
+	size_t receivedSize2 = 0;
+	size_t receivedSize3 = 0;
+	bool isSuccess = true;
+
+	// Receive results
+	Byte *rxBuff1 = new Byte[m_BUFF_MAX_SIZE];
+	Byte *rxBuff2 = new Byte[m_BUFF_MAX_SIZE];
+	Byte *rxBuff3 = new Byte[m_BUFF_MAX_SIZE];
+
+	if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+	{
+		printf("Memory allocation error.\n");
+		return false;
+	}
+
+	receivedSize = m_consumer.ReceiveData(rxBuff1,
+		m_BUFF_MAX_SIZE);
+	LOG_MSG_DEBUG("Received %zu bytes on %s.\n",
+		receivedSize,
+		m_consumer.m_fromChannelName.c_str());
+
+	receivedSize2 = m_consumer2.ReceiveData(rxBuff2,
+		m_BUFF_MAX_SIZE);
+	LOG_MSG_DEBUG("Received %zu bytes on %s.\n",
+		receivedSize2,
+		m_consumer2.m_fromChannelName.c_str());
+
+	receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3,
+		m_BUFF_MAX_SIZE);
+	LOG_MSG_DEBUG("Received %zu bytes on %s.\n",
+		receivedSize3,
+		m_defaultConsumer.m_fromChannelName.c_str());
+
+	// Compare results
+	if (!CompareResultVsGolden(m_sendBuffer1,
+		m_sendSize1,
+		rxBuff1,
+		receivedSize))
+	{
+		LOG_MSG_ERROR("Comparison of Buffer0 Failed!");
+		isSuccess = false;
+	}
+
+	char recievedBuffer[256] = {0};
+	char SentBuffer[256] = {0};
+
+	size_t j;
+	for(j = 0; j < m_sendSize1; j++)
+		snprintf(&SentBuffer[3*j], sizeof(SentBuffer) - (3*j + 1), " %02X", m_sendBuffer1[j]);
+	for(j = 0; j < receivedSize; j++)
+		snprintf(&recievedBuffer[3*j], sizeof(recievedBuffer) - (3*j + 1), " %02X", rxBuff1[j]);
+	printf("Expected Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n",
+		m_sendSize1,SentBuffer,receivedSize,recievedBuffer);
+	recievedBuffer[0] = 0;
+
+	for(j = 0; j < m_sendSize2; j++)
+		snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3*j + 1), " %02X", m_sendBuffer2[j]);
+	for(j = 0; j < receivedSize2; j++)
+		snprintf(&recievedBuffer[3*j], sizeof(recievedBuffer) - (3*j + 1), " %02X", rxBuff2[j]);
+	printf("Expected Value2 (%zu)\n%s\n, Received Value2(%zu)\n%s\n",
+		m_sendSize2,SentBuffer,receivedSize2,recievedBuffer);
+	recievedBuffer[0] = 0;
+
+	for(j = 0; j < m_sendSize3; j++)
+		snprintf(&SentBuffer[3*j], sizeof(SentBuffer) - (3*j + 1), " %02X", m_sendBuffer3[j]);
+	for(j = 0; j < receivedSize3; j++)
+		snprintf(&recievedBuffer[3*j], sizeof(recievedBuffer) - (3*j + 1), " %02X", rxBuff3[j]);
+	printf("Expected Value3 (%zu)\n%s\n, Received Value3(%zu)\n%s\n",
+		m_sendSize3,SentBuffer,receivedSize3,recievedBuffer);
+	recievedBuffer[0] = 0;
+
+	isSuccess &= CompareResultVsGolden(m_sendBuffer2,
+		m_sendSize2, rxBuff2, receivedSize2);
+	isSuccess &= CompareResultVsGolden(m_sendBuffer3,
+		m_sendSize3, rxBuff3, receivedSize3);
+
+	delete[] rxBuff1;
+	delete[] rxBuff2;
+	delete[] rxBuff3;
+
+	return isSuccess;
+}
+
+// This function creates three IPv4 bypass routing entries and commits them.
+bool IpaFilteringEthernetBridgingTestFixture::CreateThreeIPv4BypassRoutingTables(const char *bypass0, const char *bypass1,
+	const char *bypass2)
+{
+	LOG_MSG_DEBUG("Entering");
+	struct ipa_ioc_add_rt_rule *rt_rule0 = 0, *rt_rule1 = 0,*rt_rule2 = 0;
+	struct ipa_rt_rule_add *rt_rule_entry;
+
+	rt_rule0 = (struct ipa_ioc_add_rt_rule *)
+		calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			1*sizeof(struct ipa_rt_rule_add));
+	if(!rt_rule0) {
+		LOG_MSG_ERROR("calloc failed to allocate rt_rule0");
+		return false;
+	}
+	rt_rule1 = (struct ipa_ioc_add_rt_rule *)
+		calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			1*sizeof(struct ipa_rt_rule_add));
+	if(!rt_rule1) {
+		LOG_MSG_ERROR("calloc failed to allocate rt_rule1");
+		Free(rt_rule0);
+		return false;
+	}
+	rt_rule2 = (struct ipa_ioc_add_rt_rule *)
+		calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			1*sizeof(struct ipa_rt_rule_add));
+	if(!rt_rule2) {
+		LOG_MSG_ERROR("calloc failed to allocate rt_rule2");
+		Free(rt_rule0);
+		Free(rt_rule1);
+		return false;
+	}
+
+	rt_rule0->num_rules = 1;
+	rt_rule0->ip = IPA_IP_v4;
+	rt_rule0->commit = true;
+	strlcpy(rt_rule0->rt_tbl_name, bypass0, sizeof(rt_rule0->rt_tbl_name));
+
+	rt_rule_entry = &rt_rule0->rules[0];
+	rt_rule_entry->at_rear = 0;
+	rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+
+	rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+	rt_rule_entry->rule.attrib.u.v4.dst_addr = 0xaabbccdd;
+	rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0x00000000;// All Packets will get a "Hit"
+	if (false == m_routing.AddRoutingRule(rt_rule0))
+	{
+		LOG_MSG_ERROR("Routing rule addition(rt_rule0) failed!\n");
+		Free (rt_rule2);
+		Free (rt_rule1);
+		Free (rt_rule0);
+		return false;
+	}
+
+	rt_rule1->num_rules = 1;
+	rt_rule1->ip = IPA_IP_v4;
+	rt_rule1->commit = true;
+	strlcpy(rt_rule1->rt_tbl_name, bypass1, sizeof(rt_rule1->rt_tbl_name));
+	rt_rule_entry = &rt_rule1->rules[0];
+	rt_rule_entry->at_rear = 0;
+	rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+	rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+	rt_rule_entry->rule.attrib.u.v4.dst_addr = 0xaabbccdd;
+	rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0x00000000;// All Packets will get a "Hit"
+	if (false == m_routing.AddRoutingRule(rt_rule1))
+	{
+		LOG_MSG_ERROR("Routing rule addition(rt_rule1) failed!\n");
+		Free (rt_rule2);
+		Free (rt_rule1);
+		Free (rt_rule0);
+		return false;
+	}
+
+
+	rt_rule2->num_rules = 1;
+	rt_rule2->ip = IPA_IP_v4;
+	rt_rule2->commit = true;
+	strlcpy(rt_rule2->rt_tbl_name, bypass2, sizeof(rt_rule2->rt_tbl_name));
+	rt_rule_entry = &rt_rule2->rules[0];
+	rt_rule_entry->at_rear = 0;
+	rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+	rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+	rt_rule_entry->rule.attrib.u.v4.dst_addr = 0xaabbccdd;
+	rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0x00000000;// All Packets will get a "Hit"
+	if (false == m_routing.AddRoutingRule(rt_rule2))
+	{
+		LOG_MSG_ERROR("Routing rule addition(rt_rule2)\n");
+		Free (rt_rule2);
+		Free (rt_rule1);
+		Free (rt_rule0);
+		return false;
+	}
+
+	Free (rt_rule2);
+	Free (rt_rule1);
+	Free (rt_rule0);
+	LOG_MSG_DEBUG("Leaving");
+	return true;
+}
+
+// This function creates three IPv6 bypass routing entries and commits them.
+bool IpaFilteringEthernetBridgingTestFixture::CreateThreeIPv6BypassRoutingTables (const char *bypass0, const char *bypass1,
+	const char *bypass2)
+{
+	LOG_MSG_DEBUG("Entering");
+	struct ipa_ioc_add_rt_rule *rt_rule0 = 0, *rt_rule1 = 0,
+		*rt_rule2 = 0;
+	struct ipa_rt_rule_add *rt_rule_entry;
+
+	rt_rule0 = (struct ipa_ioc_add_rt_rule *)
+		calloc(1,sizeof(struct ipa_ioc_add_rt_rule) +
+			1*sizeof(struct ipa_rt_rule_add));
+	if(!rt_rule0) {
+		LOG_MSG_ERROR("calloc failed to allocate rt_rule0\n");
+		return false;
+	}
+	rt_rule1 = (struct ipa_ioc_add_rt_rule *)
+		calloc(1,sizeof(struct ipa_ioc_add_rt_rule) +
+			1*sizeof(struct ipa_rt_rule_add));
+	if(!rt_rule1) {
+		LOG_MSG_ERROR("calloc failed to allocate rt_rule1\n");
+		Free(rt_rule0);
+		return false;
+	}
+	rt_rule2 = (struct ipa_ioc_add_rt_rule *)
+		calloc(1,sizeof(struct ipa_ioc_add_rt_rule) +
+			1*sizeof(struct ipa_rt_rule_add));
+	if(!rt_rule2) {
+		LOG_MSG_ERROR("calloc failed to allocate rt_rule2\n");
+		Free(rt_rule0);
+		Free(rt_rule1);
+		return false;
+	}
+
+	rt_rule0->num_rules = 1;
+	rt_rule0->ip = IPA_IP_v6;
+	rt_rule0->commit = true;
+	strlcpy(rt_rule0->rt_tbl_name, bypass0, sizeof(rt_rule0->rt_tbl_name));
+
+	rt_rule_entry = &rt_rule0->rules[0];
+	rt_rule_entry->at_rear = 0;
+	rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+	rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0xaabbccdd;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0xeeff0011;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0x22334455;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0x66778899;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;// All Packets will get a "Hit"
+	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+	if (false == m_routing.AddRoutingRule(rt_rule0))
+	{
+		LOG_MSG_ERROR("Routing rule addition(rt_rule0)");
+		Free (rt_rule2);
+		Free (rt_rule1);
+		Free (rt_rule0);
+		return false;
+	}
+
+	rt_rule1->num_rules = 1;
+	rt_rule1->ip = IPA_IP_v6;
+	rt_rule1->commit = true;
+	strlcpy(rt_rule1->rt_tbl_name, bypass1, sizeof(rt_rule1->rt_tbl_name));
+	rt_rule_entry = &rt_rule1->rules[0];
+	rt_rule_entry->at_rear = 0;
+	rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+	rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0xaabbccdd;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0xeeff0011;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0x22334455;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0x66778899;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;// All Packets will get a "Hit"
+	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+	if (false == m_routing.AddRoutingRule(rt_rule1))
+	{
+		LOG_MSG_ERROR("Routing rule addition(rt_rule1)");
+		Free (rt_rule2);
+		Free (rt_rule1);
+		Free (rt_rule0);
+		return false;
+	}
+
+	rt_rule2->num_rules = 1;
+	rt_rule2->ip = IPA_IP_v6;
+	rt_rule2->commit = true;
+	strlcpy(rt_rule2->rt_tbl_name, bypass2, sizeof(rt_rule2->rt_tbl_name));
+	rt_rule_entry = &rt_rule2->rules[0];
+	rt_rule_entry->at_rear = 0;
+	rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+	rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0xaabbccdd;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0xeeff0011;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0x22334455;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0x66778899;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;// All Packets will get a "Hit"
+	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+	if (false == m_routing.AddRoutingRule(rt_rule2))
+	{
+		LOG_MSG_ERROR("Routing rule addition(rt_rule2)");
+		Free (rt_rule2);
+		Free (rt_rule1);
+		Free (rt_rule0);
+		return false;
+	}
+
+	Free (rt_rule2);
+	Free (rt_rule1);
+	Free (rt_rule0);
+	LOG_MSG_DEBUG("Leaving function\n");
+	return true;
+}
+
+bool IpaFilteringEthernetBridgingTestFixture::Run()
+{
+	bool res = false;
+	bool isSuccess = false;
+
+	LOG_MSG_DEBUG("Entering");
+
+	// Add the relevant filtering rules
+	res = AddRules();
+	if (false == res) {
+		LOG_MSG_ERROR("Failed adding filtering rules");
+		return false;
+	}
+
+	// Load input data (IP packet) from file
+	res = LoadFiles(m_IpaIPType);
+	if (false == res) {
+		LOG_MSG_ERROR("Failed loading files");
+		return false;
+	}
+
+	res = ModifyPackets();
+	if (false == res) {
+		LOG_MSG_ERROR("Failed to modify packets");
+		return false;
+	}
+
+	// Send first packet
+	isSuccess = m_pCurrentProducer->SendData(m_sendBuffer1,
+		m_sendSize1);
+	if (false == isSuccess)
+	{
+		LOG_MSG_ERROR("SendData failure");
+		return false;
+	}
+
+	// Send second packet
+	isSuccess = m_pCurrentProducer->SendData(m_sendBuffer2,
+		m_sendSize2);
+	if (false == isSuccess)
+	{
+		LOG_MSG_ERROR("SendData failure");
+		return false;
+	}
+
+	// Send third packet
+	isSuccess = m_pCurrentProducer->SendData(m_sendBuffer3,
+		m_sendSize3);
+	if (false == isSuccess)
+	{
+		LOG_MSG_ERROR("SendData failure");
+		return false;
+	}
+
+	// Receive packets from the channels and compare results
+	isSuccess = ReceivePacketsAndCompare();
+
+	LOG_MSG_DEBUG("Leaving function returning %d", isSuccess);
+
+	return isSuccess;
+} // Run()
+
+
+IpaFilteringEthernetBridgingTestFixture::~IpaFilteringEthernetBridgingTestFixture()
+{
+	m_sendSize1 = 0;
+	m_sendSize2 = 0;
+	m_sendSize3 = 0;
+}
+
+static const size_t m_BUFF_MAX_SIZE = 1024;
+static Filtering m_filtering;
+static RoutingDriverWrapper m_routing;
+
+InterfaceAbstraction m_producer;
+InterfaceAbstraction m_producer2; // Pipe with ETH2 header removal
+InterfaceAbstraction *m_pCurrentProducer;
+InterfaceAbstraction m_consumer;
+InterfaceAbstraction m_consumer2;
+InterfaceAbstraction m_defaultConsumer;
+
+Byte m_sendBuffer1[m_BUFF_MAX_SIZE];
+Byte m_sendBuffer2[m_BUFF_MAX_SIZE];
+Byte m_sendBuffer3[m_BUFF_MAX_SIZE];
+size_t m_sendSize1;
+size_t m_sendSize2;
+size_t m_sendSize3;
+enum ipa_ip_type m_IpaIPType;
+
+RoutingDriverWrapper IpaFilteringEthernetBridgingTestFixture::m_routing;
+Filtering IpaFilteringEthernetBridgingTestFixture::m_filtering;
+
+const uint8_t IpaFilteringEthernetBridgingTestFixture::m_ETH2_DST_ADDR[ETH_ALEN] =
+{
+	0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x11
+};
+
+const uint8_t IpaFilteringEthernetBridgingTestFixture::m_ETH2_SRC_ADDR[ETH_ALEN] =
+{
+	0x22, 0xee, 0xdd, 0xcc, 0xbb, 0xaa
+};
+
+const uint8_t IpaFilteringEthernetBridgingTestFixture::m_MAC_ADDR_MASK_ALL[ETH_ALEN] =
+{
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+

+ 104 - 0
kernel-tests/FilteringEthernetBridgingTestFixture.h

@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <cstring> // for memcpy
+#include "hton.h" // for htonl
+#include "InterfaceAbstraction.h"
+#include "Constants.h"
+#include "Logger.h"
+#include "TestsUtils.h"
+#include "Filtering.h"
+#include "RoutingDriverWrapper.h"
+#include "IPAFilteringTable.h"
+
+#define IPV4_DST_ADDR_OFFSET (16)
+#define IPV4_SRC_PORT_OFFSET (20)
+#define IPV4_DST_PORT_OFFSET (20+2)
+
+#define DST_ADDR_LSB_OFFSET_IPV4 (19)
+#define DST_ADDR_LSB_OFFSET_IPV6 (39)
+
+class IpaFilteringEthernetBridgingTestFixture : public TestBase
+{
+public:
+	virtual bool ModifyPackets() = 0;
+	virtual bool AddRules() = 0;
+
+	IpaFilteringEthernetBridgingTestFixture();
+
+	bool Setup();
+
+	bool Teardown();
+
+	virtual bool LoadFiles(enum ipa_ip_type ip);
+
+	bool ReceivePacketsAndCompare();
+
+	// This function creates three IPv4 bypass routing entries and commits them.
+	bool CreateThreeIPv4BypassRoutingTables (const char *bypass0, const char *bypass1,
+		const char *bypass2);
+
+	// This function creates three IPv6 bypass routing entries and commits them.
+	bool CreateThreeIPv6BypassRoutingTables (const char *bypass0, const char *bypass1,
+		const char *bypass2);
+
+	bool Run();
+
+	~IpaFilteringEthernetBridgingTestFixture();
+
+	static const size_t m_BUFF_MAX_SIZE = 1024;
+	static const uint8_t m_ETH2_DST_ADDR[ETH_ALEN];
+	static const uint8_t m_ETH2_SRC_ADDR[ETH_ALEN];
+	static const uint8_t m_MAC_ADDR_MASK_ALL[ETH_ALEN];
+	static Filtering m_filtering;
+	static RoutingDriverWrapper m_routing;
+
+	InterfaceAbstraction m_producer;
+	InterfaceAbstraction m_producer2; // Pipe with ETH2 header removal
+	InterfaceAbstraction *m_pCurrentProducer;
+	InterfaceAbstraction m_consumer;
+	InterfaceAbstraction m_consumer2;
+	InterfaceAbstraction m_defaultConsumer;
+
+	Byte m_sendBuffer1[m_BUFF_MAX_SIZE];
+	Byte m_sendBuffer2[m_BUFF_MAX_SIZE];
+	Byte m_sendBuffer3[m_BUFF_MAX_SIZE];
+	size_t m_sendSize1;
+	size_t m_sendSize2;
+	size_t m_sendSize3;
+	enum ipa_ip_type m_IpaIPType;
+
+private:
+};
+

+ 700 - 0
kernel-tests/FilteringEthernetBridgingTests.cpp

@@ -0,0 +1,700 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FilteringEthernetBridgingTestFixture.h"
+
+/*---------------------------------------------------------------------------*/
+/* Test 00: Destination IP address and subnet mask match against LAN subnet  */
+/*---------------------------------------------------------------------------*/
+class IpaFilterEthIPv4Test00 : public IpaFilteringEthernetBridgingTestFixture
+{
+public:
+	IpaFilterEthIPv4Test00()
+	{
+		m_name = "IpaFilterEthIPv4Test00";
+		m_description =
+		"Filtering block test 01 - Ethernet Bridge, ETH2 filters, \
+		IPv4 address (EP Filtering Table, \
+		Insert all rules in a single commit) \
+		1. Generate and commit three routing tables. \
+		Each table contains a single \"bypass\" rule \
+		(all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit 3 ETH2 filtering rules: \
+		All MAC DST == (aabbccddee11) traffic goes to routing table 0 \
+		All MAC SRC == (22eeddccbbaa) traffic goes to routing table 1 \
+		All (1)                       traffic goes to routing table 2";
+		m_minIPAHwType = IPA_HW_v2_5;
+		m_maxIPAHwType = IPA_HW_MAX;
+		Register(*this);
+		m_pCurrentProducer = &m_producer2;
+	}
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering");
+
+		const char bypass0[] = "bypass0";
+		const char bypass1[] = "bypass1";
+		const char bypass2[] = "bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeIPv4BypassRoutingTables");
+			return false;
+		}
+
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			LOG_MSG_ERROR(
+				"m_routing.GetRoutingTable(&routing_table0=0x%p)",
+				&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			LOG_MSG_ERROR(
+				"m_routing.GetRoutingTable(&routing_table1=0x%p)",
+				&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			LOG_MSG_ERROR(
+				"m_routing.GetRoutingTable(&routing_table2=0x%p)",
+				&routing_table2);
+			return false;
+		}
+
+		// Create 3 filter rules
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST2_PROD,false,3);
+
+		// Configuring Filtering Rule 0 - ETH2 DST
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.rule.retain_hdr = 1; // retain header removed in producer pipe
+		flt_rule_entry.flt_rule_hdl = -1; // return value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl; // Handle corresponding to routing table 0
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_MAC_DST_ADDR_ETHER_II; // Filter using ETH2 DST address
+		memcpy(flt_rule_entry.rule.attrib.dst_mac_addr_mask,
+				m_MAC_ADDR_MASK_ALL,
+				sizeof(flt_rule_entry.rule.attrib.dst_mac_addr_mask)); // ETH2 DST address mask
+		memcpy(flt_rule_entry.rule.attrib.dst_mac_addr,
+				m_ETH2_DST_ADDR,
+				sizeof(flt_rule_entry.rule.attrib.dst_mac_addr)); // ETH2 DST address
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			LOG_MSG_ERROR ("Adding RuleTable(0) to Filtering");
+			return false;
+		} else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x",
+				FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,
+				FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule 1 - ETH2 SRC
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; // Handle corresponding to routing table 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_MAC_SRC_ADDR_ETHER_II; // Filter using ETH2 SRC address
+		memcpy(flt_rule_entry.rule.attrib.src_mac_addr_mask,
+			m_MAC_ADDR_MASK_ALL,
+			sizeof(flt_rule_entry.rule.attrib.src_mac_addr_mask)); // ETH2 SRC address mask
+		memcpy(flt_rule_entry.rule.attrib.src_mac_addr,
+			m_ETH2_SRC_ADDR,
+			sizeof(flt_rule_entry.rule.attrib.src_mac_addr)); // ETH2 SRC address
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			LOG_MSG_ERROR ("Adding RuleTable(1) to Filtering");
+			return false;
+		} else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x",
+				FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,
+				FilterTable0.ReadRuleFromTable(1)->status);
+		}
+
+		// Configuring Filtering Rule 2 - Accept all
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table2.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000; // Accept all
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000; // Has no effect
+		if (((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable()))
+		{
+			LOG_MSG_ERROR ("Adding RuleTable(2) to Filtering");
+			return false;
+		} else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x",
+				FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,
+				FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		LOG_MSG_DEBUG("Leaving function\n");
+		return true;
+
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		memcpy(&m_sendBuffer1[ETH2_DST_ADDR_OFFSET],
+			m_ETH2_DST_ADDR, ETH_ALEN);
+
+		memcpy(&m_sendBuffer2[ETH2_DST_ADDR_OFFSET],
+			m_ETH2_DST_ADDR, ETH_ALEN);
+		m_sendBuffer2[ETH2_DST_ADDR_OFFSET] =  0x00;
+		memcpy(&m_sendBuffer2[ETH2_SRC_ADDR_OFFSET],
+			m_ETH2_SRC_ADDR, ETH_ALEN);
+
+		// swap destination and source addresses so that both
+		// rule0 and rule1 are miss and rule2 (accept all) is hit
+		memcpy(&m_sendBuffer3[ETH2_DST_ADDR_OFFSET],
+			m_ETH2_SRC_ADDR, ETH_ALEN);
+		memcpy(&m_sendBuffer3[ETH2_SRC_ADDR_OFFSET],
+			m_ETH2_DST_ADDR, ETH_ALEN);
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test 01: Destination IP address and subnet mask match against LAN subnet  */
+/*---------------------------------------------------------------------------*/
+class IpaFilterEthIPv4Test01 : public IpaFilteringEthernetBridgingTestFixture
+{
+public:
+	IpaFilterEthIPv4Test01()
+	{
+		m_name = "IpaFilterEthIPv4Test01";
+		m_description =
+			"Filtering block test 01 - Ethernet Bridge, ETH2 filters, \
+			IPv4 address (EP Filtering Table, \
+			Insert all rules in a single commit) \
+			1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule \
+			(all data goes to output pipe 0, 1  and 2 (accordingly)) \
+			2. Generate and commit 3 ETH2 filtering rules: \
+			All MAC DST == (aabbccddee11) traffic goes to routing table 0 \
+			All MAC ETH TYPE ==    (0800) traffic goes to routing table 1 \
+			All (1)                       traffic goes to routing table 2";
+		m_minIPAHwType = IPA_HW_v2_5;
+		m_maxIPAHwType = IPA_HW_MAX;
+		Register(*this);
+		m_pCurrentProducer = &m_producer2;
+	}
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering");
+
+		const char bypass0[] = "bypass0";
+		const char bypass1[] = "bypass1";
+		const char bypass2[] = "bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeIPv4BypassRoutingTables");
+			return false;
+		}
+
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			LOG_MSG_ERROR(
+				"m_routing.GetRoutingTable(&routing_table0=0x%p)",
+				&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table1=0x%p)",
+				&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			LOG_MSG_ERROR(
+				"m_routing.GetRoutingTable(&routing_table2=0x%p)",
+				&routing_table2);
+			return false;
+		}
+
+		// Create 3 filter rules
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST2_PROD,false,3);
+
+		// Configuring Filtering Rule 0 - ETH2 DST
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.rule.retain_hdr = 1; // retain header removed in producer pipe
+		flt_rule_entry.flt_rule_hdl = -1; // return value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl;
+
+		// DST
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_MAC_DST_ADDR_ETHER_II;
+		memcpy(flt_rule_entry.rule.attrib.dst_mac_addr_mask,
+			m_MAC_ADDR_MASK_ALL,
+			sizeof(flt_rule_entry.rule.attrib.dst_mac_addr_mask));
+		memcpy(flt_rule_entry.rule.attrib.dst_mac_addr,
+			m_ETH2_DST_ADDR,
+			sizeof(flt_rule_entry.rule.attrib.dst_mac_addr));
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			LOG_MSG_ERROR ("Adding RuleTable(0) to Filtering");
+			return false;
+		} else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x",
+				FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,
+				FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule 1 - ETH2 type
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_MAC_ETHER_TYPE;
+		flt_rule_entry.rule.attrib.ether_type = ETH_P_IP;
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			LOG_MSG_ERROR ("Adding RuleTable(1) to Filtering");
+			return false;
+		} else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x",
+				FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,
+				FilterTable0.ReadRuleFromTable(1)->status);
+		}
+
+		// Configuring Filtering Rule 2 - Accept all
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table2.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000; // Accept all
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000; // Has no effect
+		if (((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable()))
+		{
+			LOG_MSG_ERROR ("Adding RuleTable(2) to Filtering");
+			return false;
+		} else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x",
+				FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,
+				FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		LOG_MSG_DEBUG("Leaving function\n");
+		return true;
+
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		uint16_t ether_type = ETH_P_IP;
+		uint16_t wrong_ether_type = 0x1234;
+
+		// DST && SRC correct
+		memcpy(&m_sendBuffer1[ETH2_DST_ADDR_OFFSET],
+			m_ETH2_DST_ADDR, ETH_ALEN);
+		memcpy(&m_sendBuffer1[ETH2_SRC_ADDR_OFFSET],
+			m_ETH2_SRC_ADDR, ETH_ALEN);
+
+		// DST is wrong, ETH2 type is correct
+		memcpy(&m_sendBuffer2[ETH2_DST_ADDR_OFFSET],
+			m_ETH2_DST_ADDR, ETH_ALEN);
+		m_sendBuffer2[ETH2_DST_ADDR_OFFSET] = 0x00;
+		memcpy(&m_sendBuffer2[ETH2_ETH_TYPE_OFFSET],
+			&ether_type, sizeof(ether_type));
+
+		// DST is wrong, ETH2 type is wrong
+		memcpy(&m_sendBuffer3[ETH2_DST_ADDR_OFFSET],
+			m_ETH2_DST_ADDR, ETH_ALEN);
+		m_sendBuffer3[ETH2_DST_ADDR_OFFSET] = 0x00;
+		memcpy(&m_sendBuffer3[ETH2_ETH_TYPE_OFFSET],
+			&wrong_ether_type, sizeof(wrong_ether_type));
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test 02: Destination IP address and subnet mask match against LAN subnet  */
+/*---------------------------------------------------------------------------*/
+class IpaFilterEthIPv4Test02 : public IpaFilteringEthernetBridgingTestFixture
+{
+public:
+	IpaFilterEthIPv4Test02()
+	{
+		m_name = "IpaFilterEthIPv4Test02";
+		m_description =
+			"Filtering block test 02 - Ethernet Bridge, ETH2 filters, \
+			IPv4 address (EP Filtering Table, \
+			Insert all rules in a single commit) \
+			1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule \
+			(all data goes to output pipe 0, 1  and 2 (accordingly)) \
+			2. Generate and commit 3 ETH2 filtering rules: \
+			All MAC SRC == (22eeddccbbaa) traffic goes to routing table 0 \
+			All MAC ETH TYPE ==    (0801) traffic goes to routing table 1 \
+			All (1)                       traffic goes to routing table 2";
+		m_minIPAHwType = IPA_HW_v2_5;
+		m_maxIPAHwType = IPA_HW_MAX;
+		Register(*this);
+		m_pCurrentProducer = &m_producer2;
+	}
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering");
+
+		const char bypass0[] = "bypass0";
+		const char bypass1[] = "bypass1";
+		const char bypass2[] = "bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeIPv4BypassRoutingTables");
+			return false;
+		}
+
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			LOG_MSG_ERROR(
+				"m_routing.GetRoutingTable(&routing_table0=0x%p)",
+				&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table1=0x%p)",
+				&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			LOG_MSG_ERROR(
+				"m_routing.GetRoutingTable(&routing_table2=0x%p)",
+				&routing_table2);
+			return false;
+		}
+
+		// Create 3 filter rules
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST2_PROD,false,3);
+
+		// Configuring Filtering Rule 0 - ETH2 SRC
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.rule.retain_hdr = 1; // retain header removed in producer pipe
+		flt_rule_entry.flt_rule_hdl = -1; // return value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_MAC_SRC_ADDR_ETHER_II;
+		memcpy(flt_rule_entry.rule.attrib.src_mac_addr_mask,
+			m_MAC_ADDR_MASK_ALL,
+			sizeof(flt_rule_entry.rule.attrib.src_mac_addr_mask));
+		memcpy(flt_rule_entry.rule.attrib.src_mac_addr,
+			m_ETH2_SRC_ADDR,
+			sizeof(flt_rule_entry.rule.attrib.src_mac_addr));
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			LOG_MSG_ERROR ("Adding RuleTable(0) to Filtering");
+			return false;
+		} else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x",
+				FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,
+				FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule 1 - ETH2 type
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_MAC_ETHER_TYPE;
+		flt_rule_entry.rule.attrib.ether_type = ETH_P_IP + 1;
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			LOG_MSG_ERROR ("Adding RuleTable(1) to Filtering");
+			return false;
+		} else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x",
+				FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,
+				FilterTable0.ReadRuleFromTable(1)->status);
+		}
+
+		// Configuring Filtering Rule 2 - Accept all
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table2.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000; // Accept all
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000; // Has no effect
+		if (((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable()))
+		{
+			LOG_MSG_ERROR ("Adding RuleTable(2) to Filtering");
+			return false;
+		} else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x",
+				FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,
+				FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		LOG_MSG_DEBUG("Leaving function\n");
+		return true;
+
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		uint16_t ether_type = ETH_P_IP;
+		uint16_t wrong_ether_type = 0x1234;
+
+		memcpy(&m_sendBuffer1[ETH2_SRC_ADDR_OFFSET],
+			m_ETH2_SRC_ADDR, ETH_ALEN);
+		memcpy(&m_sendBuffer1[ETH2_ETH_TYPE_OFFSET],
+			&ether_type, sizeof(ether_type));
+
+		memcpy(&m_sendBuffer2[ETH2_SRC_ADDR_OFFSET],
+			m_ETH2_SRC_ADDR, ETH_ALEN);
+		m_sendBuffer2[ETH2_SRC_ADDR_OFFSET] = 0x00;
+		memcpy(&m_sendBuffer2[ETH2_DST_ADDR_OFFSET],
+			m_ETH2_DST_ADDR, ETH_ALEN);
+		ether_type++;
+		memcpy(&m_sendBuffer2[ETH2_ETH_TYPE_OFFSET],
+			&ether_type, sizeof(ether_type));
+
+		memcpy(&m_sendBuffer3[ETH2_DST_ADDR_OFFSET],
+			m_ETH2_SRC_ADDR, ETH_ALEN);
+		memcpy(&m_sendBuffer3[ETH2_SRC_ADDR_OFFSET],
+			m_ETH2_DST_ADDR, ETH_ALEN);
+		memcpy(&m_sendBuffer3[ETH2_ETH_TYPE_OFFSET],
+			&wrong_ether_type, sizeof(wrong_ether_type));
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test 03: Destination IP address and subnet mask match against LAN subnet  */
+/*---------------------------------------------------------------------------*/
+class IpaFilterEthIPv4Test03 : public IpaFilteringEthernetBridgingTestFixture
+{
+public:
+	IpaFilterEthIPv4Test03()
+	{
+		m_name = "IpaFilterEthIPv4Test03";
+		m_description =
+			"Filtering block test 03 - Ethernet Bridge, ETH2 filters, \
+			IPv4 address (EP Filtering Table, \
+			Insert all rules in a single commit) \
+			1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule \
+			(all data goes to output pipe 0, 1  and 2 (accordingly)) \
+			2. Generate and commit 3 ETH2 filtering rules: \
+			All MAC SRC == (22eeddccbbaa) traffic goes to routing table 0 \
+			All MAC ETH TYPE ==    (0800) traffic goes to routing table 1 \
+			All (1)                       traffic goes to routing table 2";
+		m_minIPAHwType = IPA_HW_v2_5;
+		m_maxIPAHwType = IPA_HW_MAX;
+		Register(*this);
+		m_pCurrentProducer = &m_producer2;
+	}
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering");
+
+		const char bypass0[] = "bypass0";
+		const char bypass1[] = "bypass1";
+		const char bypass2[] = "bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeIPv4BypassRoutingTables");
+			return false;
+		}
+
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			LOG_MSG_ERROR(
+				"m_routing.GetRoutingTable(&routing_table0=0x%p)",
+				&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table1=0x%p)",
+				&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			LOG_MSG_ERROR(
+				"m_routing.GetRoutingTable(&routing_table2=0x%p)",
+				&routing_table2);
+			return false;
+		}
+
+		// Create 3 filter rules
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST2_PROD,false,3);
+
+		// Configuring Filtering Rule 0 - ETH2 DST
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.rule.retain_hdr = 1; // retain header removed in producer pipe
+		flt_rule_entry.flt_rule_hdl = -1; // return value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl;
+
+		// SRC
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_MAC_SRC_ADDR_ETHER_II;
+		memcpy(flt_rule_entry.rule.attrib.src_mac_addr_mask,
+			m_MAC_ADDR_MASK_ALL,
+			sizeof(flt_rule_entry.rule.attrib.src_mac_addr_mask));
+		memcpy(flt_rule_entry.rule.attrib.src_mac_addr,
+			m_ETH2_SRC_ADDR,
+			sizeof(flt_rule_entry.rule.attrib.src_mac_addr));
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			LOG_MSG_ERROR ("Adding RuleTable(0) to Filtering");
+			return false;
+		}
+
+		// Configuring Filtering Rule 1 - ETH2 type
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_MAC_ETHER_TYPE;
+		flt_rule_entry.rule.attrib.ether_type = ETH_P_IP;
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			LOG_MSG_ERROR ("Adding RuleTable(1) to Filtering");
+			return false;
+		}
+
+		// Configuring Filtering Rule 2 - Accept all
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table2.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000; // Accept all
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000; // Has no effect
+		if (((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable()))
+		{
+			LOG_MSG_ERROR ("Adding RuleTable(2) to Filtering");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("flt rule status: s0=0x%x, s1=0x%x s2=0x%x",
+			FilterTable0.ReadRuleFromTable(0)->status,
+			FilterTable0.ReadRuleFromTable(1)->status,
+			FilterTable0.ReadRuleFromTable(2)->status);
+
+		LOG_MSG_DEBUG("Leaving function\n");
+		return true;
+
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		uint16_t ether_type = ETH_P_IP;
+		uint16_t wrong_ether_type = 0x1234;
+
+		// SRC correct, DST wrong, ETH type wrong
+		memcpy(&m_sendBuffer1[ETH2_SRC_ADDR_OFFSET],
+			m_ETH2_SRC_ADDR, ETH_ALEN);
+		memcpy(&m_sendBuffer1[ETH2_DST_ADDR_OFFSET],
+			m_ETH2_DST_ADDR, ETH_ALEN);
+		m_sendBuffer1[ETH2_DST_ADDR_OFFSET] = 0x00;
+		memcpy(&m_sendBuffer1[ETH2_ETH_TYPE_OFFSET],
+			&wrong_ether_type, sizeof(wrong_ether_type));
+
+		// SRC wrong, DST wrong, ETH type correct
+		memcpy(&m_sendBuffer2[ETH2_SRC_ADDR_OFFSET],
+			m_ETH2_SRC_ADDR, ETH_ALEN);
+		m_sendBuffer2[ETH2_SRC_ADDR_OFFSET] = 0x00;
+		memcpy(&m_sendBuffer2[ETH2_DST_ADDR_OFFSET],
+			m_ETH2_DST_ADDR, ETH_ALEN);
+		m_sendBuffer2[ETH2_DST_ADDR_OFFSET] = 0x00;
+		memcpy(&m_sendBuffer2[ETH2_ETH_TYPE_OFFSET],
+			&ether_type, sizeof(ether_type));
+
+		// SRC wrong, DST correct, ETH type wrong
+		memcpy(&m_sendBuffer3[ETH2_SRC_ADDR_OFFSET],
+			m_ETH2_SRC_ADDR, ETH_ALEN);
+		m_sendBuffer3[ETH2_SRC_ADDR_OFFSET] = 0x00;
+		memcpy(&m_sendBuffer3[ETH2_DST_ADDR_OFFSET],
+			m_ETH2_DST_ADDR, ETH_ALEN);
+		memcpy(&m_sendBuffer3[ETH2_ETH_TYPE_OFFSET],
+			&wrong_ether_type, sizeof(wrong_ether_type));
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+static IpaFilterEthIPv4Test00 ipaFilterEthIPv4Test00;
+static IpaFilterEthIPv4Test01 ipaFilterEthIPv4Test01;
+static IpaFilterEthIPv4Test02 ipaFilterEthIPv4Test02;
+static IpaFilterEthIPv4Test03 ipaFilterEthIPv4Test03;

+ 8585 - 0
kernel-tests/FilteringTest.cpp

@@ -0,0 +1,8585 @@
+/*
+ * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <cstring> // for memcpy
+#include "hton.h" // for htonl
+#include "InterfaceAbstraction.h"
+#include "Constants.h"
+#include "Logger.h"
+#include "TestsUtils.h"
+#include "Filtering.h"
+#include "RoutingDriverWrapper.h"
+#include "IPAFilteringTable.h"
+
+//TODO Add Enum for IP/TCP/UDP Fields
+
+#define IP4_TOS_FIELD_OFFSET (1)
+#define IPV4_PROTOCOL_OFFSET (9)
+#define IPV6_NEXT_HDR_OFFSET (6)
+#define IPV4_SRC_ADDR_OFFSET (12)
+#define IPV4_DST_ADDR_OFFSET (16)
+#define IPV4_SRC_PORT_OFFSET (20)
+#define IPV4_DST_PORT_OFFSET (20+2)
+#define IPV6_SRC_PORT_OFFSET (40)
+#define IPV6_DST_PORT_OFFSET (40+2)
+
+#define DST_ADDR_LSB_OFFSET_IPV4 (19)
+#define DST_ADDR_LSB_OFFSET_IPV6 (39)
+
+#define IPV4_FRAGMENT_FLAGS_OFFSET (6)
+#define IPV6_FRAGMENT_FLAGS_OFFSET (42)
+#define IPV6_FRAGMENT_NEXT_HDR_OFFSET (40)
+
+#define IPv4_TCP_FLAGS_OFFSET (20+13)
+#define TCP_ACK_FLAG_MASK (0x10)
+
+#define TAG_802_1Q_OFFSET (12)
+
+extern Logger g_Logger;
+
+class IpaFilteringBlockTestFixture : public TestBase
+{
+public:
+
+	IpaFilteringBlockTestFixture():
+		m_sendSize (BUFF_MAX_SIZE),
+		m_sendSize2 (BUFF_MAX_SIZE),
+		m_sendSize3 (BUFF_MAX_SIZE),
+		m_IpaIPType(IPA_IP_v4),
+		m_extHdrType(NONE)
+	{
+		memset(m_sendBuffer, 0, sizeof(m_sendBuffer));	// First input file / IP packet
+		memset(m_sendBuffer2, 0, sizeof(m_sendBuffer2));	// Second input file / IP packet
+		memset(m_sendBuffer3, 0, sizeof(m_sendBuffer3));	// Third input file (default) / IP packet
+		m_testSuiteName.push_back("Filtering");
+	}
+
+	static int SetupKernelModule(bool en_status = 0)
+	{
+		int retval;
+		struct ipa_channel_config from_ipa_channels[3];
+		struct test_ipa_ep_cfg from_ipa_cfg[3];
+		struct ipa_channel_config to_ipa_channels[2];
+		struct test_ipa_ep_cfg to_ipa_cfg[2];
+
+		struct ipa_test_config_header header = {0};
+		struct ipa_channel_config *to_ipa_array[2];
+		struct ipa_channel_config *from_ipa_array[3];
+
+		/* From ipa configurations - 3 pipes */
+		memset(&from_ipa_cfg[0], 0, sizeof(from_ipa_cfg[0]));
+		prepare_channel_struct(&from_ipa_channels[0],
+				header.from_ipa_channels_num++,
+				IPA_CLIENT_TEST2_CONS,
+				(void *)&from_ipa_cfg[0],
+				sizeof(from_ipa_cfg[0]),
+				en_status);
+		from_ipa_array[0] = &from_ipa_channels[0];
+
+		memset(&from_ipa_cfg[1], 0, sizeof(from_ipa_cfg[1]));
+		prepare_channel_struct(&from_ipa_channels[1],
+				header.from_ipa_channels_num++,
+				IPA_CLIENT_TEST3_CONS,
+				(void *)&from_ipa_cfg[1],
+				sizeof(from_ipa_cfg[1]),
+				en_status);
+		from_ipa_array[1] = &from_ipa_channels[1];
+
+		memset(&from_ipa_cfg[2], 0, sizeof(from_ipa_cfg[2]));
+		prepare_channel_struct(&from_ipa_channels[2],
+				header.from_ipa_channels_num++,
+				IPA_CLIENT_TEST4_CONS,
+				(void *)&from_ipa_cfg[2],
+				sizeof(from_ipa_cfg[2]),
+				en_status);
+		from_ipa_array[2] = &from_ipa_channels[2];
+
+		/* To ipa configurations - 1 pipes */
+		memset(&to_ipa_cfg[0], 0, sizeof(to_ipa_cfg[0]));
+		prepare_channel_struct(&to_ipa_channels[0],
+				header.to_ipa_channels_num++,
+				IPA_CLIENT_TEST_PROD,
+				(void *)&to_ipa_cfg[0],
+				sizeof(to_ipa_cfg[0]));
+		to_ipa_array[0] = &to_ipa_channels[0];
+
+		/* header removal for Ethernet header + 8021Q header */
+		memset(&to_ipa_cfg[1], 0, sizeof(to_ipa_cfg[1]));
+		to_ipa_cfg[1].hdr.hdr_len = ETH8021Q_HEADER_LEN;
+		to_ipa_cfg[1].hdr.hdr_ofst_metadata_valid = 1;
+		to_ipa_cfg[1].hdr.hdr_ofst_metadata =
+			ETH8021Q_METADATA_OFFSET;
+		prepare_channel_struct(&to_ipa_channels[1],
+			header.to_ipa_channels_num++,
+			IPA_CLIENT_TEST2_PROD,
+			(void *)&to_ipa_cfg[1],
+			sizeof(to_ipa_cfg[1]));
+		to_ipa_array[1] = &to_ipa_channels[1];
+
+		prepare_header_struct(&header, from_ipa_array, to_ipa_array);
+
+		retval = GenericConfigureScenario(&header);
+
+		return retval;
+	}
+
+	bool Setup()
+	{
+		bool bRetVal = true;
+
+		if (SetupKernelModule() != true)
+			return bRetVal;
+
+		m_producer.Open(INTERFACE0_TO_IPA_DATA_PATH, INTERFACE0_FROM_IPA_DATA_PATH);
+		m_producer2.Open(INTERFACE4_TO_IPA_DATA_PATH, INTERFACE4_FROM_IPA_DATA_PATH);
+
+		m_consumer.Open(INTERFACE1_TO_IPA_DATA_PATH, INTERFACE1_FROM_IPA_DATA_PATH);
+		m_consumer2.Open(INTERFACE2_TO_IPA_DATA_PATH, INTERFACE2_FROM_IPA_DATA_PATH);
+		m_defaultConsumer.Open(INTERFACE3_TO_IPA_DATA_PATH, INTERFACE3_FROM_IPA_DATA_PATH);
+
+		if (!m_routing.DeviceNodeIsOpened())
+		{
+			printf("Routing block is not ready for immediate commands!\n");
+			return false;
+		}
+
+		if (!m_filtering.DeviceNodeIsOpened())
+		{
+			printf("Filtering block is not ready for immediate commands!\n");
+			return false;
+		}
+		m_routing.Reset(IPA_IP_v4); // This will issue a Reset command to the Filtering as well
+		m_routing.Reset(IPA_IP_v6); // This will issue a Reset command to the Filtering as well
+		return true;
+	} // Setup()
+
+	bool Setup(bool en_status = false)
+	{
+		bool bRetVal = true;
+
+		if (SetupKernelModule(en_status) != true)
+			return bRetVal;
+
+		m_producer.Open(INTERFACE0_TO_IPA_DATA_PATH, INTERFACE0_FROM_IPA_DATA_PATH);
+
+		m_consumer.Open(INTERFACE1_TO_IPA_DATA_PATH, INTERFACE1_FROM_IPA_DATA_PATH);
+		m_consumer2.Open(INTERFACE2_TO_IPA_DATA_PATH, INTERFACE2_FROM_IPA_DATA_PATH);
+		m_defaultConsumer.Open(INTERFACE3_TO_IPA_DATA_PATH, INTERFACE3_FROM_IPA_DATA_PATH);
+
+		if (!m_routing.DeviceNodeIsOpened())
+		{
+			printf("Routing block is not ready for immediate commands!\n");
+			return false;
+		}
+
+		if (!m_filtering.DeviceNodeIsOpened())
+		{
+			printf("Filtering block is not ready for immediate commands!\n");
+			return false;
+		}
+		m_routing.Reset(IPA_IP_v4); // This will issue a Reset command to the Filtering as well
+		m_routing.Reset(IPA_IP_v6); // This will issue a Reset command to the Filtering as well
+		return true;
+	} // Setup()
+
+	bool Teardown()
+	{
+		m_producer.Close();
+		m_producer2.Close();
+		m_consumer.Close();
+		m_consumer2.Close();
+		m_defaultConsumer.Close();
+		return true;
+	} // Teardown()
+
+	virtual bool LoadFiles(enum ipa_ip_type ip)
+	{
+		string fileName;
+
+		if (IPA_IP_v4 == ip) {
+			fileName = "Input/IPv4_1";
+		} else {
+			fileName = "Input/IPv6";
+		}
+
+		if (!LoadDefaultPacket(ip, m_extHdrType, m_sendBuffer, m_sendSize)) {
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+		printf ("Loaded %zu Bytes to Buffer 1\n",m_sendSize);
+
+		if (!LoadDefaultPacket(ip, m_extHdrType, m_sendBuffer2, m_sendSize2)) {
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+		printf ("Loaded %zu Bytes to Buffer 2\n",m_sendSize2);
+
+		if (!LoadDefaultPacket(ip, m_extHdrType, m_sendBuffer3, m_sendSize3)) {
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+		printf ("Loaded %zu Bytes to Buffer 3\n",m_sendSize3);
+
+		return true;
+	}
+
+	inline bool VerifyStatusReceived(size_t SendSize, size_t RecvSize)
+	{
+		size_t stts_size = sizeof(struct ipa3_hw_pkt_status);
+
+		if (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) {
+			stts_size = sizeof(struct ipa3_hw_pkt_status_hw_v5_0);
+		}
+
+		if ((RecvSize <= SendSize) ||
+			((RecvSize - SendSize) != stts_size)){
+			printf("received buffer size does not match! sent:receive [%zu]:[%zu]\n",SendSize,RecvSize);
+			return false;
+		}
+
+		return true;
+	}
+
+	inline bool IsCacheHit(size_t SendSize, size_t RecvSize, void *Buff)
+	{
+		struct ipa3_hw_pkt_status *pStatus = (struct ipa3_hw_pkt_status *)Buff;
+
+		if (VerifyStatusReceived(SendSize,RecvSize) == false){
+			return false;
+		}
+
+		if((bool)pStatus->filt_hash){
+			printf ("%s::cache hit!! \n",__FUNCTION__);
+			return true;
+		}
+
+		printf ("%s::cache miss!! \n",__FUNCTION__);
+		return false;
+	}
+
+	inline bool IsCacheHit_v5_0(size_t SendSize, size_t RecvSize, void *Buff)
+	{
+		struct ipa3_hw_pkt_status_hw_v5_0 *pStatus = (struct ipa3_hw_pkt_status_hw_v5_0 *)Buff;
+
+		if (VerifyStatusReceived(SendSize,RecvSize) == false){
+			return false;
+		}
+
+		if((bool)pStatus->filt_hash){
+			printf ("%s::cache hit!! \n",__FUNCTION__);
+			return true;
+		}
+
+		printf ("%s::cache miss!! \n",__FUNCTION__);
+		return false;
+	}
+
+	inline bool IsCacheMiss(size_t SendSize, size_t RecvSize, void *Buff)
+	{
+		struct ipa3_hw_pkt_status *pStatus = (struct ipa3_hw_pkt_status *)Buff;
+
+		if (VerifyStatusReceived(SendSize,RecvSize) == false){
+			return false;
+		}
+
+		if(!((bool)pStatus->filt_hash)){
+			printf ("%s::cache miss!! \n",__FUNCTION__);
+			return true;
+		}
+
+		printf ("%s::cache hit!! \n",__FUNCTION__);
+		return false;
+	}
+
+	inline bool IsCacheMiss_v5_0(size_t SendSize, size_t RecvSize, void *Buff)
+	{
+		struct ipa3_hw_pkt_status_hw_v5_0 *pStatus = (struct ipa3_hw_pkt_status_hw_v5_0 *)Buff;
+
+		if (VerifyStatusReceived(SendSize,RecvSize) == false){
+			return false;
+		}
+
+		if(!((bool)pStatus->filt_hash)){
+			printf ("%s::cache miss!! \n",__FUNCTION__);
+			return true;
+		}
+
+		printf ("%s::cache hit!! \n",__FUNCTION__);
+		return false;
+	}
+
+
+	bool ReceivePacketAndCompareFrom(InterfaceAbstraction& cons, Byte* send,
+									 size_t send_sz, bool shouldBeHit)
+	{
+		size_t receivedSize = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+
+		if (NULL == rxBuff1)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = cons.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, cons.m_fromChannelName.c_str());
+
+		// Compare results
+		isSuccess &= CompareResultVsGolden_w_Status(send, send_sz, rxBuff1, receivedSize);
+
+		if (shouldBeHit) {
+			isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+				IsCacheHit_v5_0(send_sz, receivedSize, rxBuff1) : IsCacheHit(send_sz, receivedSize, rxBuff1);
+		}
+		else
+		{
+			isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+				IsCacheMiss_v5_0(send_sz, receivedSize, rxBuff1) : IsCacheMiss(send_sz, receivedSize, rxBuff1);
+		}
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+		size_t j;
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		for(j = 0; j < m_sendSize; j++)
+			snprintf(&sentBuffer[3 * j], sentBufferSize - (3 * j + 1), " %02X", send[j]);
+		for(j = 0; j < receivedSize; j++)
+			snprintf(&recievedBuffer[3 * j], recievedBufferSize - (3 * j + 1), " %02X", rxBuff1[j]);
+		printf("Expected Value (%zu)\n%s\n, Received Value1(%zu)\n%s\n",send_sz,sentBuffer,receivedSize,recievedBuffer);
+
+		delete[] rxBuff1;
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		//receivedSize = excp_cons.ReceiveData(rxBuff1, 0x400);
+		//printf("Received %zu bytes on %s.\n", receivedSize, excp_cons.m_fromChannelName.c_str());
+
+		return isSuccess;
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool pkt1_cmp_succ, pkt2_cmp_succ, pkt3_cmp_succ;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		memset(rxBuff1, 0, 0x400);
+		memset(rxBuff2, 0, 0x400);
+		memset(rxBuff3, 0, 0x400);
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer2.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer2.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		// Compare results
+		pkt1_cmp_succ = CompareResultVsGolden(m_sendBuffer, m_sendSize, rxBuff1, receivedSize);
+		pkt2_cmp_succ = CompareResultVsGolden(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+		pkt3_cmp_succ = CompareResultVsGolden(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		size_t recievedBufferSize =
+			MAX3(receivedSize, receivedSize2, receivedSize3) * 3;
+		size_t sentBufferSize =
+			MAX3(m_sendSize, m_sendSize2, m_sendSize3) * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+		size_t j;
+
+		if (NULL == recievedBuffer || NULL == sentBuffer) {
+			printf("Memory allocation error\n");
+			return false;
+		}
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+		for(j = 0; j < m_sendSize; j++)
+			snprintf(&sentBuffer[3 * j], sentBufferSize - (3 * j + 1), " %02X", m_sendBuffer[j]);
+		for(j = 0; j < receivedSize; j++)
+			snprintf(&recievedBuffer[3 * j], recievedBufferSize - (3 * j + 1), " %02X", rxBuff1[j]);
+		printf("Expected Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n-->Value1 %s\n",
+			m_sendSize,sentBuffer,receivedSize,recievedBuffer,
+			pkt1_cmp_succ?"Match":"no Match");
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+		for(j = 0; j < m_sendSize2; j++)
+			snprintf(&sentBuffer[3 * j], sentBufferSize - (3 * j + 1), " %02X", m_sendBuffer2[j]);
+		for(j = 0; j < receivedSize2; j++)
+			snprintf(&recievedBuffer[3 * j], recievedBufferSize - (3 * j + 1), " %02X", rxBuff2[j]);
+		printf("Expected Value2 (%zu)\n%s\n, Received Value2(%zu)\n%s\n-->Value2 %s\n",
+			m_sendSize2,sentBuffer,receivedSize2,recievedBuffer,
+			pkt2_cmp_succ?"Match":"no Match");
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+		for(j = 0; j < m_sendSize3; j++)
+			snprintf(&sentBuffer[3 * j], sentBufferSize - (3 * j + 1), " %02X", m_sendBuffer3[j]);
+		for(j = 0; j < receivedSize3; j++)
+			snprintf(&recievedBuffer[3 * j], recievedBufferSize - (3 * j + 1), " %02X", rxBuff3[j]);
+		printf("Expected Value3 (%zu)\n%s\n, Received Value3(%zu)\n%s\n-->Value3 %s\n",
+			m_sendSize3,sentBuffer,receivedSize3,recievedBuffer,
+			pkt3_cmp_succ?"Match":"no Match");
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return pkt1_cmp_succ && pkt2_cmp_succ && pkt3_cmp_succ;
+	}
+
+	// This function creates three IPv4 bypass routing entries and commits them.
+	bool CreateThreeIPv4BypassRoutingTables (const char * bypass0, const char * bypass1, const char * bypass2)
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		struct ipa_ioc_add_rt_rule *rt_rule0 = 0, *rt_rule1 = 0,*rt_rule2 = 0;
+		struct ipa_rt_rule_add *rt_rule_entry;
+
+		rt_rule0 = (struct ipa_ioc_add_rt_rule *)
+			calloc(1,
+					sizeof(struct ipa_ioc_add_rt_rule) +
+						1*sizeof(struct ipa_rt_rule_add)
+				);
+		if(!rt_rule0) {
+			printf("calloc failed to allocate rt_rule0 in %s\n",__FUNCTION__);
+			return false;
+		}
+		rt_rule1 = (struct ipa_ioc_add_rt_rule *)
+			calloc(1,
+					sizeof(struct ipa_ioc_add_rt_rule) +
+						1*sizeof(struct ipa_rt_rule_add)
+				);
+		if(!rt_rule1) {
+			printf("calloc failed to allocate rt_rule1 in %s\n",__FUNCTION__);
+			Free(rt_rule0);
+			return false;
+		}
+		rt_rule2 = (struct ipa_ioc_add_rt_rule *)
+			calloc(1,
+					sizeof(struct ipa_ioc_add_rt_rule) +
+						1*sizeof(struct ipa_rt_rule_add)
+				);
+		if(!rt_rule2) {
+			printf("calloc failed to allocate rt_rule2 in %s\n",__FUNCTION__);
+			Free(rt_rule0);
+			Free(rt_rule1);
+			return false;
+		}
+
+		rt_rule0->num_rules = 1;
+		rt_rule0->ip = IPA_IP_v4;
+		rt_rule0->commit = true;
+		strlcpy(rt_rule0->rt_tbl_name, bypass0, sizeof(rt_rule0->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule0->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;//Setting
+		//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // TODO Header Inserion - gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr = 0xaabbccdd;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0x00000000;// All Packets will get a "Hit"
+		if (false == m_routing.AddRoutingRule(rt_rule0))
+		{
+			printf("Routing rule addition(rt_rule0) failed!\n");
+			Free (rt_rule2);
+			Free (rt_rule1);
+			Free (rt_rule0);
+			return false;
+		}
+
+
+		rt_rule1->num_rules = 1;
+		rt_rule1->ip = IPA_IP_v4;
+		rt_rule1->commit = true;
+		strlcpy(rt_rule1->rt_tbl_name, bypass1, sizeof(rt_rule1->rt_tbl_name));
+		rt_rule_entry = &rt_rule1->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // TODO Header Inserion - gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr = 0xaabbccdd;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0x00000000;// All Packets will get a "Hit"
+		if (false == m_routing.AddRoutingRule(rt_rule1))
+		{
+			printf("Routing rule addition(rt_rule1) failed!\n");
+			Free (rt_rule2);
+			Free (rt_rule1);
+			Free (rt_rule0);
+			return false;
+		}
+
+
+		rt_rule2->num_rules = 1;
+		rt_rule2->ip = IPA_IP_v4;
+		rt_rule2->commit = true;
+		strlcpy(rt_rule2->rt_tbl_name, bypass2, sizeof(rt_rule2->rt_tbl_name));
+		rt_rule_entry = &rt_rule2->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+		//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // TODO Header Inserion - gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr = 0xaabbccdd;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0x00000000;// All Packets will get a "Hit"
+		if (false == m_routing.AddRoutingRule(rt_rule2))
+		{
+			printf("Routing rule addition(rt_rule2) failed!\n");
+			Free (rt_rule2);
+			Free (rt_rule1);
+			Free (rt_rule0);
+			return false;
+		}
+
+
+		Free (rt_rule2);
+		Free (rt_rule1);
+		Free (rt_rule0);
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	// This function creates three IPv6 bypass routing entries and commits them.
+	bool CreateThreeIPv6BypassRoutingTables (const char * bypass0, const char * bypass1, const char * bypass2)
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		struct ipa_ioc_add_rt_rule *rt_rule0 = 0, *rt_rule1 = 0,*rt_rule2 = 0;
+		struct ipa_rt_rule_add *rt_rule_entry;
+
+		rt_rule0 = (struct ipa_ioc_add_rt_rule *)
+			calloc(1,
+					sizeof(struct ipa_ioc_add_rt_rule) +
+						1*sizeof(struct ipa_rt_rule_add)
+				);
+		if(!rt_rule0) {
+			printf("calloc failed to allocate rt_rule0 in %s\n",__FUNCTION__);
+			return false;
+		}
+		rt_rule1 = (struct ipa_ioc_add_rt_rule *)
+			calloc(1,
+					sizeof(struct ipa_ioc_add_rt_rule) +
+						1*sizeof(struct ipa_rt_rule_add)
+				);
+		if(!rt_rule1) {
+			printf("calloc failed to allocate rt_rule1 in %s\n",__FUNCTION__);
+			Free(rt_rule0);
+			return false;
+		}
+		rt_rule2 = (struct ipa_ioc_add_rt_rule *)
+			calloc(1,
+					sizeof(struct ipa_ioc_add_rt_rule) +
+						1*sizeof(struct ipa_rt_rule_add)
+				);
+		if(!rt_rule2) {
+			printf("calloc failed to allocate rt_rule2 in %s\n",__FUNCTION__);
+			Free(rt_rule0);
+			Free(rt_rule1);
+			return false;
+		}
+
+		rt_rule0->num_rules = 1;
+		rt_rule0->ip = IPA_IP_v6;
+		rt_rule0->commit = true;
+		strlcpy(rt_rule0->rt_tbl_name, bypass0, sizeof(rt_rule0->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule0->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;//Setting
+		//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // TODO Header Inserion - gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0xaabbccdd;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0xeeff0011;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0x22334455;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0x66778899;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;// All Packets will get a "Hit"
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		if (false == m_routing.AddRoutingRule(rt_rule0))
+		{
+			printf("Routing rule addition(rt_rule0) failed!\n");
+			Free (rt_rule2);
+			Free (rt_rule1);
+			Free (rt_rule0);
+			return false;
+		}
+
+
+		rt_rule1->num_rules = 1;
+		rt_rule1->ip = IPA_IP_v6;
+		rt_rule1->commit = true;
+		strlcpy(rt_rule1->rt_tbl_name, bypass1, sizeof(rt_rule1->rt_tbl_name));
+		rt_rule_entry = &rt_rule1->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // TODO Header Inserion - gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0xaabbccdd;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0xeeff0011;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0x22334455;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0x66778899;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;// All Packets will get a "Hit"
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		if (false == m_routing.AddRoutingRule(rt_rule1))
+		{
+			printf("Routing rule addition(rt_rule1) failed!\n");
+			Free (rt_rule2);
+			Free (rt_rule1);
+			Free (rt_rule0);
+			return false;
+		}
+
+
+		rt_rule2->num_rules = 1;
+		rt_rule2->ip = IPA_IP_v6;
+		rt_rule2->commit = true;
+		strlcpy(rt_rule2->rt_tbl_name, bypass2, sizeof(rt_rule2->rt_tbl_name));
+		rt_rule_entry = &rt_rule2->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+		//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // TODO Header Inserion - gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0xaabbccdd;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0xeeff0011;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0x22334455;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0x66778899;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;// All Packets will get a "Hit"
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		if (false == m_routing.AddRoutingRule(rt_rule2))
+		{
+			printf("Routing rule addition(rt_rule2) failed!\n");
+			Free (rt_rule2);
+			Free (rt_rule1);
+			Free (rt_rule0);
+			return false;
+		}
+
+
+		Free (rt_rule2);
+		Free (rt_rule1);
+		Free (rt_rule0);
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	bool GetThreeIPv6BypassRoutingTables(uint32_t *Hndl0, uint32_t *Hndl1, uint32_t *Hndl2)
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv6BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v6;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v6;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v6;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		*Hndl0 = routing_table0.hdl;
+		*Hndl1 = routing_table1.hdl;
+		*Hndl2 = routing_table2.hdl;
+
+		return true;
+
+	}
+
+	void print_packets(size_t receivedSize, size_t m_sendSize, size_t recievedBufferSize, size_t sentBufferSize, Byte *rxBuff, Byte *m_sendBuffer,  char *recievedBuffer, char *sentBuffer)
+	{
+		size_t j;
+
+		for(j = 0; j < m_sendSize; j++) {
+			snprintf(&sentBuffer[3 * j], sentBufferSize - 3 * j,
+				" %02X", m_sendBuffer[j]);
+		}
+		for(j = 0; j < receivedSize; j++) {
+			snprintf(&recievedBuffer[3 * j], recievedBufferSize- 3 * j,
+				" %02X", rxBuff[j]);
+		}
+		printf("Expected Value (%zu)\n%s\n, Received Value(%zu)\n%s\n",m_sendSize,sentBuffer,receivedSize,recievedBuffer);
+	}
+
+	virtual bool ModifyPackets() = 0;
+	virtual bool AddRules() = 0;
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		// Add the relevant filtering rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding filtering rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(m_IpaIPType);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		res = ModifyPackets();
+		if (false == res) {
+			printf("Failed to modify packets.\n");
+			return false;
+		}
+
+		// Send first packet
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		printf("Leaving %s, %s(), Returning %d\n",__FUNCTION__, __FILE__,isSuccess);
+
+		return isSuccess;
+	} // Run()
+
+
+	~IpaFilteringBlockTestFixture()
+	{
+		m_sendSize = 0;
+		m_sendSize2 = 0;
+		m_sendSize3 = 0;
+	}
+
+	static Filtering m_filtering;
+	static RoutingDriverWrapper m_routing;
+	InterfaceAbstraction m_producer;
+	InterfaceAbstraction m_producer2;
+	InterfaceAbstraction m_consumer;
+	InterfaceAbstraction m_consumer2;
+	InterfaceAbstraction m_defaultConsumer;
+
+	static const size_t BUFF_MAX_SIZE = 1024;
+
+	Byte m_sendBuffer[BUFF_MAX_SIZE];	// First input file / IP packet
+	Byte m_sendBuffer2[BUFF_MAX_SIZE];	// Second input file / IP packet
+	Byte m_sendBuffer3[BUFF_MAX_SIZE];	// Third input file (default) / IP packet
+	size_t m_sendSize;
+	size_t m_sendSize2;
+	size_t m_sendSize3;
+	enum ipa_ip_type m_IpaIPType;
+	enum ipv6_ext_hdr_type m_extHdrType;
+
+private:
+};
+
+RoutingDriverWrapper IpaFilteringBlockTestFixture::m_routing;
+Filtering IpaFilteringBlockTestFixture::m_filtering;
+
+
+/*---------------------------------------------------------------------------*/
+/* Test001: Destination IP address and subnet mask match against LAN subnet  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest001 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest001()
+	{
+		m_name = "IpaFilteringBlockTest001";
+		m_description =
+		"Filtering block test 001 - Destination IP address and subnet mask match against LAN subnet (Global Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules: (DST & Mask Match). \
+			All DST_IP == (127.0.0.1 & 255.0.0.255)traffic goes to routing table 0 \
+			All DST_IP == (192.169.1.1 & 255.0.0.255)traffic goes to routing table 1 \
+			All DST_IP == (192.169.1.2 & 255.0.0.255)traffic goes to routing table 2";
+		m_maxIPAHwType = IPA_HW_v2_6L;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,3);
+		printf("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1 // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80101; // Filter DST_IP == 192.168.1.1.
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+		}
+
+		// Configuring Filtering Rule No.2 // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80101);//192.168.1.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test002: Destination IP address exact match against broadcast IP address  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest002 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest002()
+	{
+		m_name = "IpaFilteringBlockTest002";
+		m_description =
+		"Filtering block test 002 - Destination IP address exact match against broadcast IP address (Global Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules (MASK = 0xFF..FF). \
+			All DST_IP == 127.0.0.1 traffic goes to routing table 0 \
+			All DST_IP == 192.169.1.1 traffic goes to routing table 1 \
+			All DST_IP == 192.169.1.2 traffic goes to routing table 2";
+		m_maxIPAHwType = IPA_HW_v2_6L;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF; // Exact Match
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80101; // Filter DST_IP == 192.168.1.1.
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80101);//192.168.1.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+
+
+/*---------------------------------------------------------------------------*/
+/* Test003: Destination UDP port exact match against DHCP port  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest003 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest003()
+	{
+		m_name = "IpaFilteringBlockTest003";
+		m_description =
+			"Filtering block test 003 - Destination UDP port exact match against DHCP port (Global Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules . \
+			All DST_UDP_PORT == 546 (DHCP Client)traffic goes to routing table 0 \
+			All DST_UDP_PORT == 547 (DHCP Server) traffic goes to routing table 1 \
+			All DST_UDP_PORT == 500 (Non DHCP) traffic goes to routing table 2";
+		m_maxIPAHwType = IPA_HW_v2_6L;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+		flt_rule_entry.rule.attrib.dst_port = 546; // DHCP Client Port No 546
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.dst_port = 547; // DHCP Server Port No 547
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.dst_port = 500; // Non-DHCP Port
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		unsigned short port;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Port should be switched to Network Mode.
+		port = ntohs(546);//DHCP Client Port
+		memcpy (&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = ntohs(547);//DHCP Server Port
+		memcpy (&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = ntohs(500);//Non - DHCP Port
+		memcpy (&m_sendBuffer3[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*------------------------------------------------------------------------------*/
+/* Test004: Firewall filtering rules based on source and destination port ranges  */
+/*------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest004 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest004()
+	{
+		m_name = "IpaFilteringBlockTest004";
+		m_description =
+		"Filtering block test 004 - Firewall filtering rules based on source and destination port ranges (Global Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules . \
+			All (5 >= SRC_PORT_RANGE >= 15) & (50 >= DST_PORT_RANGE >= 150) traffic goes to routing table 0 \
+			All (15 >= SRC_PORT_RANGE >= 25) & (150 >= DST_PORT_RANGE >= 250) traffic goes to routing table 1 \
+			All (25 >= SRC_PORT_RANGE >= 35) & (250 >= DST_PORT_RANGE >= 350) traffic goes to routing table 2";
+		m_maxIPAHwType = IPA_HW_v2_6L;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_SRC_PORT_RANGE | IPA_FLT_DST_PORT_RANGE;
+		//TODO: Fix from here.....
+		flt_rule_entry.rule.attrib.src_port_lo =5;
+		flt_rule_entry.rule.attrib.src_port_hi =15;
+		flt_rule_entry.rule.attrib.dst_port_lo =50;
+		flt_rule_entry.rule.attrib.dst_port_hi =150;
+
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.src_port_lo = 15;
+		flt_rule_entry.rule.attrib.src_port_hi = 25;
+		flt_rule_entry.rule.attrib.dst_port_lo = 150;
+		flt_rule_entry.rule.attrib.dst_port_hi = 250;
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.src_port_lo = 25;
+		flt_rule_entry.rule.attrib.src_port_hi = 35;
+		flt_rule_entry.rule.attrib.dst_port_lo = 250;
+		flt_rule_entry.rule.attrib.dst_port_hi = 350;
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		unsigned short port;
+
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		port = htons(10);
+		memcpy(&m_sendBuffer[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+		port = htons(100);
+		memcpy(&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = htons(20);
+		memcpy(&m_sendBuffer2[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+		port = htons(200);
+		memcpy(&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = htons(30);
+		memcpy(&m_sendBuffer3[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+		port = htons(300);
+		memcpy(&m_sendBuffer3[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		return true;
+	}// ModifyPacktes ()
+};
+/*---------------------------------------------------------------------------*/
+/* Test005: Destination IP address exact match against broadcast IP address  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest005 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest005()
+	{
+		m_name = "IpaFilteringBlockTest005";
+		m_description =
+		"Filtering block test 005 - Filtering Based on Protocol type (TCP/UDP/ICMP) (Global Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All UDP traffic goes to routing table 0 \
+			All TCP traffic goes to routing table 1 \
+			All ICMP traffic goes to routing table 2";
+		m_maxIPAHwType = IPA_HW_v2_6L;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+//		Test Description:
+//		1. Generate and commit two routing tables.
+//			Each table will contain a single "bypass" rule (all data goes to output pipe 0 and 1 (accordingly))
+//		2. Generate and commit two filtering rules.
+//			All UDP traffic goes to routing table 1
+//			All TCP traffic goes to routing table 2
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name,bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_PROTOCOL;
+		flt_rule_entry.rule.attrib.u.v4.protocol = 17; // Filter only UDP Packets.
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.protocol = 6; // Filter only TCP Packets.
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.protocol = 1; // Filter only ICMP Packets.
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		m_sendBuffer[IPV4_PROTOCOL_OFFSET] = 0x11;// UDP 0x11 = 17
+		m_sendBuffer2[IPV4_PROTOCOL_OFFSET] = 0x06;// TCP 0x06 = 6
+		m_sendBuffer3[IPV4_PROTOCOL_OFFSET] = 0x01;// ICMP 0x01 = 1
+		return true;
+	}// ModifyPacktes ()
+};
+
+
+/*---------------------------------------------------------------------------*/
+/* Test006: Destination IP address and subnet mask match against LAN subnet  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest006 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest006()
+	{
+		m_name = "IpaFilteringBlockTest006";
+		m_description =
+		"Filtering block test 006 - Destination IP address and subnet mask match against LAN subnet (Global Filtering Table, each rule is added in a Insert using a dedicated single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules: (DST & Mask Match). \
+			All DST_IP == (127.0.0.1 & 255.0.0.255)traffic goes to routing table 0 \
+			All DST_IP == (192.169.1.1 & 255.0.0.255)traffic goes to routing table 1 \
+			All DST_IP == (192.169.1.2 & 255.0.0.255)traffic goes to routing table 2";
+		m_maxIPAHwType = IPA_HW_v2_6L;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0,FilterTable1,FilterTable2;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+		FilterTable1.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+		FilterTable2.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+		printf("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1 // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80101; // Filter DST_IP == 192.168.1.1.
+		if (
+				((uint8_t)-1 == FilterTable1.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable1.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable1.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable1.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.2 // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == FilterTable2.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable2.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable2.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable2.ReadRuleFromTable(0)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80101);//192.168.1.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test007: Destination IP address exact match against broadcast IP address  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest007 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest007()
+	{
+		m_name = "IpaFilteringBlockTest007";
+		m_description =
+		"Filtering block test 007 - Destination IP address exact match against broadcast IP address (Global Filtering Table, each rule is added in a Insert using a dedicated single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules (MASK = 0xFF..FF). \
+			All DST_IP == 127.0.0.1 traffic goes to routing table 0 \
+			All DST_IP == 192.169.1.1 traffic goes to routing table 1 \
+			All DST_IP == 192.169.1.2 traffic goes to routing table 2";
+		m_maxIPAHwType = IPA_HW_v2_6L;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		//		Test Description:
+		//		1. Generate and commit three routing tables.
+		//			Each table will contain a single "bypass" rule (all data goes to output pipe 0, 1 and 2(accordingly))
+		//		2. Generate and commit three filtering rules (each in different Filtering Table)
+		//			All Filter DST_IP == 127.0.0.1 traffic goes to routing table 1
+		//			All Filter DST_IP == 192.168.1.1 traffic goes to routing table 2
+		//			All Filter DST_IP == 192.168.1.2 traffic goes to routing table 3
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2,sizeof(routing_table2.name) );
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0,FilterTable1,FilterTable2;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+		FilterTable1.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+		FilterTable2.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF; // Exact Match
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80101; // Filter DST_IP == 192.168.1.1.
+		if (
+				((uint8_t)-1 == FilterTable1.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable1.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable1.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable1.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == FilterTable2.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable2.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable2.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable2.ReadRuleFromTable(0)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80101);//192.168.1.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+
+
+/*---------------------------------------------------------------------------*/
+/* Test008: Destination UDP port exact match against DHCP port  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest008 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest008()
+	{
+		m_name = "IpaFilteringBlockTest008";
+		m_description =
+		"Filtering block test 008 - Destination UDP port exact match against DHCP port (Global Filtering Table, each rule is added in a Insert using a dedicated single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules . \
+			All DST_UDP_PORT == 546 (DHCP Client)traffic goes to routing table 0 \
+			All DST_UDP_PORT == 547 (DHCP Server) traffic goes to routing table 1 \
+			All DST_UDP_PORT == 500 (Non DHCP) traffic goes to routing table 2";
+		m_maxIPAHwType = IPA_HW_v2_6L;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+//		Test Description:
+//		1. Generate and commit three routing tables.
+//			Each table will contain a single "bypass" rule (all data goes to output pipe 0, 1  and 2 (accordingly))
+//		2. Generate and commit Three filtering rules.
+//			All DEST_IP == 127.0.0.1 traffic goes to routing table 0
+//			All DEST_IP == 192.169.1.1 traffic goes to routing table 1
+//			Non Matching traffic goes to routing table 3
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0,FilterTable1,FilterTable2;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+		FilterTable1.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+		FilterTable2.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+		flt_rule_entry.rule.attrib.dst_port = 546; // DHCP Client Port No 546
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.dst_port = 547; // DHCP Server Port No 547
+		if (
+				((uint8_t)-1 == FilterTable1.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable1.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable1.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable1.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.dst_port = 500; // Non-DHCP Port
+
+		if (
+				((uint8_t)-1 == FilterTable2.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable2.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable2.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable2.ReadRuleFromTable(0)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		unsigned short port;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Port should be switched to Network Mode.
+		port = ntohs(546);//DHCP Client Port
+		memcpy (&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = ntohs(547);//DHCP Server Port
+		memcpy (&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = ntohs(500);//Non - DHCP Port
+		memcpy (&m_sendBuffer3[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*------------------------------------------------------------------------------*/
+/* Test009: Firewall filtering rules based on source and destination port ranges  */
+/*------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest009 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest009()
+	{
+		m_name = "IpaFilteringBlockTest009";
+		m_description =
+		"Filtering block test 009 - Firewall filtering rules based on source and destination port ranges (Global Filtering Table, each rule is added in a Insert using a dedicated single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules . \
+			All (5 >= SRC_PORT_RANGE >= 15) & (50 >= DST_PORT_RANGE >= 150) traffic goes to routing table 0 \
+			All (15 >= SRC_PORT_RANGE >= 25) & (150 >= DST_PORT_RANGE >= 250) traffic goes to routing table 1 \
+			All (25 >= SRC_PORT_RANGE >= 35) & (250 >= DST_PORT_RANGE >= 350) traffic goes to routing table 2";
+		m_maxIPAHwType = IPA_HW_v2_6L;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+//		Test Description:
+//		1. Generate and commit two routing tables.
+//			Each table will contain a single "bypass" rule (all data goes to output pipe 0 and 1 (accordingly))
+//		2. Generate and commit two filtering rules.
+//			All UDP traffic goes to routing table 1
+//			All TCP traffic goes to routing table 2
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0,FilterTable1,FilterTable2;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+		FilterTable1.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+		FilterTable2.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_SRC_PORT_RANGE | IPA_FLT_DST_PORT_RANGE;
+		//TODO: Fix from here.....
+		flt_rule_entry.rule.attrib.src_port_lo =5;
+		flt_rule_entry.rule.attrib.src_port_hi =15;
+		flt_rule_entry.rule.attrib.dst_port_lo =50;
+		flt_rule_entry.rule.attrib.dst_port_hi =150;
+
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.src_port_lo = 15;
+		flt_rule_entry.rule.attrib.src_port_hi = 25;
+		flt_rule_entry.rule.attrib.dst_port_lo = 150;
+		flt_rule_entry.rule.attrib.dst_port_hi = 250;
+
+		if (
+				((uint8_t)-1 == FilterTable1.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable1.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable1.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable1.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.src_port_lo = 25;
+		flt_rule_entry.rule.attrib.src_port_hi = 35;
+		flt_rule_entry.rule.attrib.dst_port_lo = 250;
+		flt_rule_entry.rule.attrib.dst_port_hi = 350;
+
+		if (
+				((uint8_t)-1 == FilterTable2.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable2.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable2.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable2.ReadRuleFromTable(0)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		unsigned short port;
+
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		port = htons(10);
+		memcpy(&m_sendBuffer[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+		port = htons(100);
+		memcpy(&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = htons(20);
+		memcpy(&m_sendBuffer2[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+		port = htons(200);
+		memcpy(&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = htons(30);
+		memcpy(&m_sendBuffer3[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+		port = htons(300);
+		memcpy(&m_sendBuffer3[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		return true;
+	}// ModifyPacktes ()
+};
+/*---------------------------------------------------------------------------*/
+/* Test010: Destination IP address exact match against broadcast IP address  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest010 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest010()
+	{
+		m_name = "IpaFilteringBlockTest010";
+		m_description =
+		"Filtering block test 010 - Filtering Based on Protocol type (TCP/UDP/ICMP) (Global Filtering Table, each rule is added in a Insert using a dedicated single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All UDP traffic goes to routing table 0 \
+			All TCP traffic goes to routing table 1 \
+			All ICMP traffic goes to routing table 2";
+		m_maxIPAHwType = IPA_HW_v2_6L;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+//		Test Description:
+//		1. Generate and commit two routing tables.
+//			Each table will contain a single "bypass" rule (all data goes to output pipe 0 and 1 (accordingly))
+//		2. Generate and commit two filtering rules.
+//			All UDP traffic goes to routing table 1
+//			All TCP traffic goes to routing table 2
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0,FilterTable1,FilterTable2;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+		FilterTable1.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+		FilterTable2.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,true,1);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_PROTOCOL;
+		flt_rule_entry.rule.attrib.u.v4.protocol = 17; // Filter only UDP Packets.
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.protocol = 6; // Filter only TCP Packets.
+		if (
+				((uint8_t)-1 == FilterTable1.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable1.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable1.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable1.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.protocol = 1; // Filter only ICMP Packets.
+
+		if (
+				((uint8_t)-1 == FilterTable2.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable2.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable2.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable2.ReadRuleFromTable(0)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		m_sendBuffer[IPV4_PROTOCOL_OFFSET] = 0x11;// UDP 0x11 = 17
+		m_sendBuffer2[IPV4_PROTOCOL_OFFSET] = 0x06;// TCP 0x06 = 6
+		m_sendBuffer3[IPV4_PROTOCOL_OFFSET] = 0x01;// ICMP 0x01 = 1
+		return true;
+	}// ModifyPacktes ()
+};
+
+
+/*---------------------------------------------------------------------------*/
+/* Test021: Destination IP address and subnet mask match against LAN subnet  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest021 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest021()
+	{
+		m_name = "IpaFilteringBlockTest021";
+		m_description =
+		"Filtering block test 021 - Destination IP address and subnet mask match against LAN subnet (End-Point specific Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules: (DST & Mask Match). \
+			All DST_IP == (127.0.0.1 & 255.0.0.255)traffic goes to routing table 0 \
+			All DST_IP == (192.169.1.1 & 255.0.0.255)traffic goes to routing table 1 \
+			All DST_IP == (192.169.1.2 & 255.0.0.255)traffic goes to routing table 2";
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		printf("%s route table handle = %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+		printf("%s route table handle = %u\n", bypass1, routing_table1.hdl);
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+		printf("%s route table handle = %u\n", bypass2, routing_table2.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,3);
+		printf("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1 // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80101; // Filter DST_IP == 192.168.1.1.
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2 // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl1=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl2=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80101);//192.168.1.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test022: Destination IP address exact match against broadcast IP address  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest022 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest022()
+	{
+		m_name = "IpaFilteringBlockTest022";
+		m_description =
+		"Filtering block test 022 - Destination IP address exact match against broadcast IP address (End-Point specific Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules (MASK = 0xFF..FF). \
+			All DST_IP == 127.0.0.1 traffic goes to routing table 0 \
+			All DST_IP == 192.169.1.1 traffic goes to routing table 1 \
+			All DST_IP == 192.169.1.2 traffic goes to routing table 2";
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF; // Exact Match
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80101; // Filter DST_IP == 192.168.1.1.
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else {
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl1=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl2=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80101);//192.168.1.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+
+
+/*---------------------------------------------------------------------------*/
+/* Test023: Destination UDP port exact match against DHCP port 				 */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest023 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest023()
+	{
+		m_name = "IpaFilteringBlockTest023";
+		m_description =
+		"Filtering block test 023 - Destination UDP port exact match against DHCP port (End-Point specific Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules . \
+			All DST_UDP_PORT == 546 (DHCP Client)traffic goes to routing table 0 \
+			All DST_UDP_PORT == 547 (DHCP Server) traffic goes to routing table 1 \
+			All DST_UDP_PORT == 500 (Non DHCP) traffic goes to routing table 2";
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+		flt_rule_entry.rule.attrib.dst_port = 546; // DHCP Client Port No 546
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.dst_port = 547; // DHCP Server Port No 547
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.dst_port = 500; // Non-DHCP Port
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else {
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl1=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl2=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		unsigned short port;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Port should be switched to Network Mode.
+		port = ntohs(546);//DHCP Client Port
+		memcpy (&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = ntohs(547);//DHCP Server Port
+		memcpy (&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = ntohs(500);//Non - DHCP Port
+		memcpy (&m_sendBuffer3[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*------------------------------------------------------------------------------*/
+/* Test004: Firewall filtering rules based on source and destination port ranges*/
+/*------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest024 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest024()
+	{
+		m_name = "IpaFilteringBlockTest024";
+		m_description =
+		"Filtering block test 024 - Firewall filtering rules based on source and destination port ranges (End-Point specific Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules . \
+			All (5 >= SRC_PORT_RANGE >= 15) & (50 >= DST_PORT_RANGE >= 150) traffic goes to routing table 0 \
+			All (15 >= SRC_PORT_RANGE >= 25) & (150 >= DST_PORT_RANGE >= 250) traffic goes to routing table 1 \
+			All (25 >= SRC_PORT_RANGE >= 35) & (250 >= DST_PORT_RANGE >= 350) traffic goes to routing table 2";
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_SRC_PORT_RANGE | IPA_FLT_DST_PORT_RANGE;
+		//TODO: Fix from here.....
+		flt_rule_entry.rule.attrib.src_port_lo =5;
+		flt_rule_entry.rule.attrib.src_port_hi =15;
+		flt_rule_entry.rule.attrib.dst_port_lo =50;
+		flt_rule_entry.rule.attrib.dst_port_hi =150;
+
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.src_port_lo = 15;
+		flt_rule_entry.rule.attrib.src_port_hi = 25;
+		flt_rule_entry.rule.attrib.dst_port_lo = 150;
+		flt_rule_entry.rule.attrib.dst_port_hi = 250;
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.src_port_lo = 25;
+		flt_rule_entry.rule.attrib.src_port_hi = 35;
+		flt_rule_entry.rule.attrib.dst_port_lo = 250;
+		flt_rule_entry.rule.attrib.dst_port_hi = 350;
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl1=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl2=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		unsigned short port;
+
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		port = htons(10);
+		memcpy(&m_sendBuffer[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+		port = htons(100);
+		memcpy(&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = htons(20);
+		memcpy(&m_sendBuffer2[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+		port = htons(200);
+		memcpy(&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = htons(30);
+		memcpy(&m_sendBuffer3[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+		port = htons(300);
+		memcpy(&m_sendBuffer3[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		return true;
+	}// ModifyPacktes ()
+};
+/*---------------------------------------------------------------------------*/
+/* Test005: Destination IP address exact match against broadcast IP address  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest025 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest025()
+	{
+		m_name = "IpaFilteringBlockTest025";
+		m_description =
+				"Filtering block test 025 - Filtering Based on Protocol type (TCP/UDP/ICMP) (End-Point specific Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All UDP traffic goes to routing table 0 \
+			All TCP traffic goes to routing table 1 \
+			All ICMP traffic goes to routing table 2";
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+//		Test Description:
+//		1. Generate and commit two routing tables.
+//			Each table will contain a single "bypass" rule (all data goes to output pipe 0 and 1 (accordingly))
+//		2. Generate and commit two filtering rules.
+//			All UDP traffic goes to routing table 1
+//			All TCP traffic goes to routing table 2
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_PROTOCOL;
+		flt_rule_entry.rule.attrib.u.v4.protocol = 17; // Filter only UDP Packets.
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.protocol = 6; // Filter only TCP Packets.
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.protocol = 1; // Filter only ICMP Packets.
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl1=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl2=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		m_sendBuffer[IPV4_PROTOCOL_OFFSET] = 0x11;// UDP 0x11 = 17
+		m_sendBuffer2[IPV4_PROTOCOL_OFFSET] = 0x06;// TCP 0x06 = 6
+		m_sendBuffer3[IPV4_PROTOCOL_OFFSET] = 0x01;// ICMP 0x01 = 1
+		return true;
+	}// ModifyPacktes ()
+};
+
+
+/*---------------------------------------------------------------------------*/
+/* Test006: Destination IP address and subnet mask match against LAN subnet  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest026 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest026()
+	{
+		m_name = "IpaFilteringBlockTest026";
+		m_description =
+				"Filtering block test 026 - Destination IP address and subnet mask match against LAN subnet (End-Point specific Filtering Table, each rule is added in a Insert using a dedicated single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules: (DST & Mask Match). \
+			All DST_IP == (127.0.0.1 & 255.0.0.255)traffic goes to routing table 0 \
+			All DST_IP == (192.169.1.1 & 255.0.0.255)traffic goes to routing table 1 \
+			All DST_IP == (192.169.1.2 & 255.0.0.255)traffic goes to routing table 2";
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0,FilterTable1,FilterTable2;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+		FilterTable1.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+		FilterTable2.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+		printf("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1 // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80101; // Filter DST_IP == 192.168.1.1.
+		if (
+				((uint8_t)-1 == FilterTable1.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable1.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable1.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable1.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.2 // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == FilterTable2.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable2.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable2.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable2.ReadRuleFromTable(0)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80101);//192.168.1.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test007: Destination IP address exact match against broadcast IP address  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest027 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest027()
+	{
+		m_name = "IpaFilteringBlockTest027";
+		m_description =
+		"Filtering block test 027 - Destination IP address exact match against broadcast IP address (End-Point specific Filtering Table, each rule is added in a Insert using a dedicated single commit) \
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules (MASK = 0xFF..FF). \
+			All DST_IP == 127.0.0.1 traffic goes to routing table 0 \
+			All DST_IP == 192.169.1.1 traffic goes to routing table 1 \
+			All DST_IP == 192.169.1.2 traffic goes to routing table 2";
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		//		Test Description:
+		//		1. Generate and commit three routing tables.
+		//			Each table will contain a single "bypass" rule (all data goes to output pipe 0, 1 and 2(accordingly))
+		//		2. Generate and commit three filtering rules (each in different Filtering Table)
+		//			All Filter DST_IP == 127.0.0.1 traffic goes to routing table 1
+		//			All Filter DST_IP == 192.168.1.1 traffic goes to routing table 2
+		//			All Filter DST_IP == 192.168.1.2 traffic goes to routing table 3
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0,FilterTable1,FilterTable2;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+		FilterTable1.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+		FilterTable2.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // TODO: Fix this, doesn't match the Rule's Requirements
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF; // Exact Match
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80101; // Filter DST_IP == 192.168.1.1.
+		if (
+				((uint8_t)-1 == FilterTable1.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable1.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable1.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable1.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == FilterTable2.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable2.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable2.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable2.ReadRuleFromTable(0)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80101);//192.168.1.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+
+
+/*---------------------------------------------------------------------------*/
+/* Test008: Destination UDP port exact match against DHCP port  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest028 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest028()
+	{
+		m_name = "IpaFilteringBlockTest028";
+		m_description =
+		"Filtering block test 028 - Destination UDP port exact match against DHCP port (End-Point specific Filtering Table, each rule is added in a Insert using a dedicated single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules . \
+			All DST_UDP_PORT == 546 (DHCP Client)traffic goes to routing table 0 \
+			All DST_UDP_PORT == 547 (DHCP Server) traffic goes to routing table 1 \
+			All DST_UDP_PORT == 500 (Non DHCP) traffic goes to routing table 2";
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+//		Test Description:
+//		1. Generate and commit three routing tables.
+//			Each table will contain a single "bypass" rule (all data goes to output pipe 0, 1  and 2 (accordingly))
+//		2. Generate and commit Three filtering rules.
+//			All DEST_IP == 127.0.0.1 traffic goes to routing table 0
+//			All DEST_IP == 192.169.1.1 traffic goes to routing table 1
+//			Non Matching traffic goes to routing table 3
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0,FilterTable1,FilterTable2;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+		FilterTable1.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+		FilterTable2.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+		flt_rule_entry.rule.attrib.dst_port = 546; // DHCP Client Port No 546
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.dst_port = 547; // DHCP Server Port No 547
+		if (
+				((uint8_t)-1 == FilterTable1.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable1.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable1.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable1.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.dst_port = 500; // Non-DHCP Port
+
+		if (
+				((uint8_t)-1 == FilterTable2.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable2.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable2.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable2.ReadRuleFromTable(0)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		unsigned short port;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Port should be switched to Network Mode.
+		port = ntohs(546);//DHCP Client Port
+		memcpy (&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = ntohs(547);//DHCP Server Port
+		memcpy (&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = ntohs(500);//Non - DHCP Port
+		memcpy (&m_sendBuffer3[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*------------------------------------------------------------------------------*/
+/* Test009: Firewall filtering rules based on source and destination port ranges  */
+/*------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest029 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest029()
+	{
+		m_name = "IpaFilteringBlockTest029";
+		m_description =
+		"Filtering block test 029 - Firewall filtering rules based on source and destination port ranges (End-Point specific Filtering Table, each rule is added in a Insert using a dedicated single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules . \
+			All (5 >= SRC_PORT_RANGE >= 15) & (50 >= DST_PORT_RANGE >= 150) traffic goes to routing table 0 \
+			All (15 >= SRC_PORT_RANGE >= 25) & (150 >= DST_PORT_RANGE >= 250) traffic goes to routing table 1 \
+			All (25 >= SRC_PORT_RANGE >= 35) & (250 >= DST_PORT_RANGE >= 350) traffic goes to routing table 2";
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+//		Test Description:
+//		1. Generate and commit two routing tables.
+//			Each table will contain a single "bypass" rule (all data goes to output pipe 0 and 1 (accordingly))
+//		2. Generate and commit two filtering rules.
+//			All UDP traffic goes to routing table 1
+//			All TCP traffic goes to routing table 2
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0,FilterTable1,FilterTable2;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+		FilterTable1.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+		FilterTable2.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_SRC_PORT_RANGE | IPA_FLT_DST_PORT_RANGE;
+		//TODO: Fix from here.....
+		flt_rule_entry.rule.attrib.src_port_lo =5;
+		flt_rule_entry.rule.attrib.src_port_hi =15;
+		flt_rule_entry.rule.attrib.dst_port_lo =50;
+		flt_rule_entry.rule.attrib.dst_port_hi =150;
+
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.src_port_lo = 15;
+		flt_rule_entry.rule.attrib.src_port_hi = 25;
+		flt_rule_entry.rule.attrib.dst_port_lo = 150;
+		flt_rule_entry.rule.attrib.dst_port_hi = 250;
+
+		if (
+				((uint8_t)-1 == FilterTable1.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable1.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable1.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable1.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.src_port_lo = 25;
+		flt_rule_entry.rule.attrib.src_port_hi = 35;
+		flt_rule_entry.rule.attrib.dst_port_lo = 250;
+		flt_rule_entry.rule.attrib.dst_port_hi = 350;
+
+		if (
+				((uint8_t)-1 == FilterTable2.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable2.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable2.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable2.ReadRuleFromTable(0)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		unsigned short port;
+
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		port = htons(10);
+		memcpy(&m_sendBuffer[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+		port = htons(100);
+		memcpy(&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = htons(20);
+		memcpy(&m_sendBuffer2[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+		port = htons(200);
+		memcpy(&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		port = htons(30);
+		memcpy(&m_sendBuffer3[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+		port = htons(300);
+		memcpy(&m_sendBuffer3[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		return true;
+	}// ModifyPacktes ()
+};
+/*---------------------------------------------------------------------------*/
+/* Test010: Destination IP address exact match against broadcast IP address  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest030 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest030()
+	{
+		m_name = "IpaFilteringBlockTest030";
+		m_description =
+		"Filtering block test 030 - Filtering Based on Protocol type (TCP/UDP/ICMP) (End-Point specific Filtering Table, each rule is added in a Insert using a dedicated single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All UDP traffic goes to routing table 0 \
+			All TCP traffic goes to routing table 1 \
+			All ICMP traffic goes to routing table 2";
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+//		Test Description:
+//		1. Generate and commit two routing tables.
+//			Each table will contain a single "bypass" rule (all data goes to output pipe 0 and 1 (accordingly))
+//		2. Generate and commit two filtering rules.
+//			All UDP traffic goes to routing table 1
+//			All TCP traffic goes to routing table 2
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0,FilterTable1,FilterTable2;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+		FilterTable1.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+		FilterTable2.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,1);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_PROTOCOL;
+		flt_rule_entry.rule.attrib.u.v4.protocol = 17; // Filter only UDP Packets.
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.protocol = 6; // Filter only TCP Packets.
+		if (
+				((uint8_t)-1 == FilterTable1.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable1.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable1.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable1.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.protocol = 1; // Filter only ICMP Packets.
+
+		if (
+				((uint8_t)-1 == FilterTable2.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable2.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable2.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable2.ReadRuleFromTable(0)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		m_sendBuffer[IPV4_PROTOCOL_OFFSET] = 0x11;// UDP 0x11 = 17
+		m_sendBuffer2[IPV4_PROTOCOL_OFFSET] = 0x06;// TCP 0x06 = 6
+		m_sendBuffer3[IPV4_PROTOCOL_OFFSET] = 0x01;// ICMP 0x01 = 1
+		return true;
+	}// ModifyPacktes ()
+};
+/*-------------------------------------------------------------------------------------*/
+/* Test031: Filtering Based on fragment extension, End-Point specific Filtering Table  */
+/*-------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest031 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest031()
+	{
+		m_name = "IpaFilteringBlockTest031";
+		m_description =
+				"Filtering block test 031 - Filtering Based on fragment extension(End-Point specific Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit 2 filtering rules: \
+			All fragmented packets goes to routing table 0: \
+			Packets with MF flag set & \
+			Packets with MF flag set to zero and fragment offset field nonzero \
+			All other packets(non fragmented) goes to routing table 1: \
+			Packets with MF flag set to zero and fragment offset field zero goes to routing table 1";
+		Register(*this);
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables(bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_FRAGMENT;
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xaabbccdd;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;// All Packets will get a "Hit"
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl1=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		m_sendBuffer[IPV4_FRAGMENT_FLAGS_OFFSET] = 0x20;//MF=1
+		m_sendBuffer[IPV4_FRAGMENT_FLAGS_OFFSET+1] = 0x0;//MF=1
+		m_sendBuffer2[IPV4_FRAGMENT_FLAGS_OFFSET] = 0x0;//MF=0 && frag_off =126
+		m_sendBuffer2[IPV4_FRAGMENT_FLAGS_OFFSET+1] = 0x7E;//MF=0 && frag_off =126
+		m_sendBuffer3[IPV4_FRAGMENT_FLAGS_OFFSET] = 0x0;// MF=0 && frag_off =0
+		m_sendBuffer3[IPV4_FRAGMENT_FLAGS_OFFSET+1] = 0x0;// MF=0 && frag_off =0
+		return true;
+	}// ModifyPacktes ()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize3 = m_consumer2.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_consumer2.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGolden(m_sendBuffer, m_sendSize, rxBuff1, receivedSize))
+		{
+			printf("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize - 1, sentBufferSize - 1, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		recievedBuffer[0] = '\0';
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize - 1, sentBufferSize - 1, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		recievedBuffer[0] = '\0';
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize - 1, sentBufferSize - 1, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+		isSuccess &= CompareResultVsGolden(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+		isSuccess &= CompareResultVsGolden(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test050: Destination IPv6 address and Subnet Mask exact match against broadcast IP address  */
+/*---------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest050 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest050()
+	{
+		m_name = "IpaFilteringBlockTest050";
+		m_description =
+		"Filtering block test 050 - Destination IPv6 address and Mask exact match against broadcast IP address (Global Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IPv6 == 0x...AA traffic goes to routing table 1 \
+			All DST_IPv6 == 0x...BB traffic goes to routing table 2 \
+			All DST_IPv6 == 0x...CC traffic goes to routing table 3";
+		m_IpaIPType = IPA_IP_v6;
+		m_maxIPAHwType = IPA_HW_v2_6L;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv6BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v6;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v6;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v6;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v6,IPA_CLIENT_TEST_PROD,true,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // TODO: Fix this, doesn't match the Rule's Requirements
+
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x000000FF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0]		 = 0XFF020000; // Filter DST_IP
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1]		 = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2]      = 0x11223344;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677AA;
+
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677BB;
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677CC;
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xBB;
+		m_sendBuffer3[DST_ADDR_LSB_OFFSET_IPV6] = 0xCC;
+		return true;
+	}// ModifyPacktes ()
+};
+
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test051: Destination IPv6 address and Subnet Mask exact match against broadcast IP address  */
+/*---------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest051 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest051()
+	{
+		m_name = "IpaFilteringBlockTest051";
+		m_description =
+		"Filtering block test 051 - Destination IPv6 address and Mask exact match against broadcast IP address (End-Point specific Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IPv6 == 0x...AA traffic goes to routing table 1 \
+			All DST_IPv6 == 0x...BB traffic goes to routing table 2 \
+			All DST_IPv6 == 0x...CC traffic goes to routing table 3";
+		m_IpaIPType = IPA_IP_v6;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv6BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v6;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v6;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v6;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v6,IPA_CLIENT_TEST_PROD,false,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // TODO: Fix this, doesn't match the Rule's Requirements
+
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x000000FF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0]      = 0XFF020000; // Filter DST_IP
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1]      = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2]      = 0x11223344;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677AA;
+
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677BB;
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677CC;
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl1=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl2=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xBB;
+		m_sendBuffer3[DST_ADDR_LSB_OFFSET_IPV6] = 0xCC;
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test052: IPv6 Filtering Based on Protocol type (TCP/UDP/ICMP)  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest052 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest052()
+	{
+		m_name = "IpaFilteringBlockTest052";
+		m_description =
+		"Filtering block test 052 - Filtering Based on Protocol type (TCP/UDP/ICMP) (Global Filtering Table, each rule is added in a Insert using a dedicated single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All UDP traffic goes to routing table 0 \
+			All TCP traffic goes to routing table 1 \
+			All ICMP traffic goes to routing table 2";
+		m_IpaIPType = IPA_IP_v6;
+		m_extHdrType = FRAGMENT;
+		m_minIPAHwType = IPA_HW_v2_5;
+		m_maxIPAHwType = IPA_HW_v2_6L;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv6BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v6;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v6;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v6;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0,FilterTable1,FilterTable2;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v6,IPA_CLIENT_TEST_PROD,true,1);
+		FilterTable1.Init(IPA_IP_v6,IPA_CLIENT_TEST_PROD,true,1);
+		FilterTable2.Init(IPA_IP_v6,IPA_CLIENT_TEST_PROD,true,1);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_NEXT_HDR;
+		flt_rule_entry.rule.attrib.u.v6.next_hdr = 17; // Filter only UDP Packets.
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+		{
+			printf ("%s::Error Adding RuleTable(0) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v6.next_hdr = 6; // Filter only TCP Packets.
+		if (
+				((uint8_t)-1 == FilterTable1.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable1.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(1) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable1.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable1.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v6.next_hdr = 1; // Filter only ICMP Packets.
+
+		if (
+				((uint8_t)-1 == FilterTable2.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable2.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable2.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable2.ReadRuleFromTable(0)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		m_sendBuffer[IPV6_NEXT_HDR_OFFSET] = 0x2C;//FRAGMENT HEADER(44)
+		m_sendBuffer[IPV6_FRAGMENT_NEXT_HDR_OFFSET] = 0x11;// UDP 0x11 = 17
+		m_sendBuffer2[IPV6_FRAGMENT_NEXT_HDR_OFFSET] = 0x06;// TCP 0x06 = 6
+		m_sendBuffer3[IPV6_FRAGMENT_NEXT_HDR_OFFSET] = 0x01;// ICMP 0x01 = 1
+		return true;
+	}// ModifyPacktes ()
+};
+/*-------------------------------------------------------------------------------------*/
+/* Test053: Filtering Based on fragment extension, End-Point specific Filtering Table  */
+/*-------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest053 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest053()
+	{
+		m_name = "IpaFilteringBlockTest053";
+		m_description =
+				"Filtering block test 053 - Filtering Based on fragment extension(End-Point specific Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit 2 filtering rules: \
+			All fragmented packets goes to routing table 0: \
+			Packets with MF flag set & \
+			Packets with MF flag set to zero and fragment offset field nonzero \
+			All other packets(non fragmented) goes to routing table 1: \
+			Packets with MF flag set to zero and fragment offset field zero goes to routing table 1";
+		m_IpaIPType = IPA_IP_v6;
+		m_extHdrType = FRAGMENT;
+		m_minIPAHwType = IPA_HW_v2_5;
+		Register(*this);
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv6BypassRoutingTables(bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v6;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v6;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v6;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v6,IPA_CLIENT_TEST_PROD,false,2);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_FRAGMENT;
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xaabbccdd;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0xeeff0011;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x22334455;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0x66778899;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;// All Packets will get a "Hit"
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		if (
+			((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl1=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		m_sendBuffer[IPV6_NEXT_HDR_OFFSET] = 0x2C;//FRAGMENT HEADER(44)
+		m_sendBuffer[IPV6_FRAGMENT_FLAGS_OFFSET] = 0x00;//MF=1
+		m_sendBuffer[IPV6_FRAGMENT_FLAGS_OFFSET+1] = 0x1;//MF=1
+		m_sendBuffer2[IPV6_FRAGMENT_FLAGS_OFFSET] = 0x3;//MF=0 && frag_off =126
+		m_sendBuffer2[IPV6_FRAGMENT_FLAGS_OFFSET+1] = 0xF0;//MF=0 && frag_off =126
+		m_sendBuffer3[IPV6_FRAGMENT_FLAGS_OFFSET] = 0x0;// MF=0 && frag_off =0
+		m_sendBuffer3[IPV6_FRAGMENT_FLAGS_OFFSET+1] = 0x0;// MF=0 && frag_off =0
+		return true;
+	}// ModifyPacktes ()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize3 = m_consumer2.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_consumer2.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGolden(m_sendBuffer, m_sendSize, rxBuff1, receivedSize))
+		{
+			printf("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize - 1, sentBufferSize - 1, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		recievedBuffer[0] = '\0';
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize - 1, sentBufferSize - 1, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		recievedBuffer[0] = '\0';
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize - 1, sentBufferSize - 1, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+		isSuccess &= CompareResultVsGolden(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+		isSuccess &= CompareResultVsGolden(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test054: IPV6 filtering based on based on source and destination port  			*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest054 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest054()
+	{
+		m_name = "IpaFilteringBlockTest054";
+		m_description =
+		"Filtering block test 054 - IPV6 filtering rules based on source and destination port (End-Point specific Filtering Table, Insert all rules in a single commit)\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules:\
+			All (SRC_PORT = 1000) traffic goes to routing table 0 \
+			All (DST_PORT = 100) traffic goes to routing table 1 \
+			All (5 >= SRC_PORT_RANGE >= 15) traffic goes to routing table 2";
+		m_IpaIPType = IPA_IP_v6;
+		m_minIPAHwType = IPA_HW_v2_5;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv6BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v6;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v6;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v6;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v6,IPA_CLIENT_TEST_PROD,false,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_SRC_PORT;
+		flt_rule_entry.rule.attrib.src_port = 1000;
+
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
+		flt_rule_entry.rule.attrib.dst_port = 100;
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_SRC_PORT_RANGE;
+		flt_rule_entry.rule.attrib.src_port_lo = 5;
+		flt_rule_entry.rule.attrib.src_port_hi = 15;
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl1=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl2=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		unsigned short port;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+
+		port = htons(1000);
+		memcpy(&m_sendBuffer[IPV6_SRC_PORT_OFFSET], &port, sizeof(port));
+		port = htons(100);
+		memcpy(&m_sendBuffer2[IPV6_DST_PORT_OFFSET], &port, sizeof(port));
+		port = htons(10);
+		memcpy(&m_sendBuffer3[IPV6_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test060: IPV4 filtering test, non hashed priority higher than hashed priority				*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest060 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest060()
+	{
+		m_name = "IpaFilteringBlockTest060";
+		m_description =
+		"Filtering block test 060 - Rules prioritization hashable vs non-hashable rule, both rules match the same packet but non hashable has higher priority\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IP == (127.0.0.1 & 255.0.0.255)traffic goes to routing table 0 - non hashable\
+			All DST_IP == (127.0.0.1 & 255.0.0.255)traffic goes to routing table 1 - hashable\
+			All DST_IP == (192.169.1.2 & 255.0.0.255)traffic goes to routing table 2 - don't care for this specific test";
+		m_minIPAHwType = IPA_HW_v3_0;
+		Register(*this);
+
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass1, routing_table1.hdl);
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass2, routing_table2.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,3);
+		printf("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; //
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		flt_rule_entry.rule.hashable = 0; // non hashed
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1 on lower priority (second in list)
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		flt_rule_entry.rule.hashable = 1; // hashed
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.hashable = 0; // non hashed
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+
+	}
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGolden(m_sendBuffer, m_sendSize, rxBuff1, receivedSize))
+		{
+			printf("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize - 1, sentBufferSize - 1, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		recievedBuffer[0] = '\0';
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize - 1, sentBufferSize - 1, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		recievedBuffer[0] = '\0';
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize - 1, sentBufferSize - 1, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+		isSuccess &= CompareResultVsGolden(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+		isSuccess &= CompareResultVsGolden(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test061: IPV4 filtering test, hashed priority higher than non hashed priority + cache hit	*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest061 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest061()
+	{
+		m_name = "IpaFilteringBlockTest061";
+		m_description =
+		"Filtering block test 061 - Rules prioritization hashable vs non-hashable rule, both rules match the same packet but hashable has higher priority\
+		two identical packets are sent and should be catched by the hashable rule, second one shuld be hit the cache\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IP == (127.0.0.1 & 255.0.0.255)traffic goes to routing table 0 - hashable\
+			All DST_IP == (127.0.0.1 & 255.0.0.255)traffic goes to routing table 1 - non hashable\
+			All DST_IP == (192.169.1.2 & 255.0.0.255)traffic goes to routing table 2 - don't care for this specific test";
+		m_minIPAHwType = IPA_HW_v3_0;
+		Register(*this);
+
+	}
+
+	bool Setup()
+	{
+		/* we want statuses on this test */
+		return IpaFilteringBlockTestFixture::Setup(true);
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass1, routing_table1.hdl);
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass2, routing_table2.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,3);
+		printf("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; //
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		flt_rule_entry.rule.hashable = 1; // hashed
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1 on lower priority (second in list)
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		flt_rule_entry.rule.hashable = 0; // non hashed
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 3
+		flt_rule_entry.rule.hashable = 0; // non hashed
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGolden_w_Status(m_sendBuffer, m_sendSize, rxBuff1, receivedSize))
+		{
+			printf("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize, receivedSize, rxBuff1) : IsCacheMiss(m_sendSize,receivedSize,rxBuff1);
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize, sentBufferSize, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize, sentBufferSize, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize, sentBufferSize, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ? 
+			IsCacheHit_v5_0(m_sendSize2, receivedSize2, rxBuff2) : IsCacheHit(m_sendSize2,receivedSize2,rxBuff2);
+
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize3, receivedSize3, rxBuff3) : IsCacheMiss(m_sendSize3,receivedSize3,rxBuff3);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test062: IPV4 filtering test, hashed rule match, non hash doesn't match expect cache miss	*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest062 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest062()
+	{
+		m_name = "IpaFilteringBlockTest062";
+		m_description =
+		"Filtering block test 062 - Rules prioritization hashable vs non-hashable rule, only hashable matches the packets\
+		two packets with different tuple are sent and should match the hashable rule, no cache hit expected\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IP == (127.0.0.2 & 255.0.0.255)traffic goes to routing table 0 - non hashable\
+			All DST_IP == (127.0.0.1 & 255.0.0.255)traffic goes to routing table 1 - hashable\
+			All DST_IP == (192.169.1.2 & 255.0.0.255)traffic goes to routing table 2 - don't care for this specific test\
+		3. send three packets:\
+			DST_IP == 127.0.0.1 port 546\
+			DST_IP == 127.0.0.1 port 547\
+			DST_IP == 192.168.1.2";
+		m_minIPAHwType = IPA_HW_v3_0;
+		Register(*this);
+	}
+
+	bool Setup()
+	{
+		/* we want statuses on this test */
+		return IpaFilteringBlockTestFixture::Setup(true);
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass1, routing_table1.hdl);
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass2, routing_table2.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,3);
+		printf("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; //
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000002; // Filter DST_IP == 127.0.0.2.
+		flt_rule_entry.rule.hashable = 0; // non hashed
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1 on lower priority (second in list)
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		flt_rule_entry.rule.hashable = 1; // hashed
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 3
+		flt_rule_entry.rule.hashable = 0; // non hashed
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+
+	}
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+		unsigned short port;
+
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = ntohs(546);//DHCP Client Port
+		memcpy (&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = ntohs(547);//DHCP Server Port
+		memcpy (&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer2.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer2.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGolden_w_Status(m_sendBuffer, m_sendSize, rxBuff1, receivedSize))
+		{
+			printf("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize, receivedSize, rxBuff1) : IsCacheMiss(m_sendSize,receivedSize,rxBuff1);
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize, sentBufferSize, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize, sentBufferSize, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize, sentBufferSize, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize2, receivedSize2, rxBuff2) : IsCacheMiss(m_sendSize2,receivedSize2,rxBuff2);
+
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize3, receivedSize3, rxBuff3) : IsCacheMiss(m_sendSize3,receivedSize3,rxBuff3);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test063: IPV4 filtering test, hashed rule match, non hash doesn't match expect cache miss 	*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest063 : public IpaFilteringBlockTestFixture
+{
+public:
+
+	IpaFilteringBlockTest063()
+	{
+		m_name = "IpaFilteringBlockTest063";
+		m_description =
+		"Filtering block test 063 - Rules prioritization hashable vs non-hashable rule, only hashable matches the packets\
+		two packets with different tuple are sent and should match the hashable rule, no cache hit expected\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IP == (127.0.0.1 & 255.0.0.255)traffic goes to routing table 0 - hashable\
+			All DST_IP == (127.0.0.2 & 255.0.0.255)traffic goes to routing table 1 - non hashable\
+			All DST_IP == (192.169.1.2 & 255.0.0.255)traffic goes to routing table 2 - don't care for this specific test\
+		3. send three packets:\
+			DST_IP == 127.0.0.1 port 546\
+			DST_IP == 127.0.0.1 port 547\
+			DST_IP == 192.168.1.2";
+		m_minIPAHwType = IPA_HW_v3_0;
+		Register(*this);
+	}
+
+	bool Setup()
+	{
+		/* we want statuses on this test */
+		return IpaFilteringBlockTestFixture::Setup(true);
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass1, routing_table1.hdl);
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass2, routing_table2.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,3);
+		printf("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; //
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		flt_rule_entry.rule.hashable = 1; // hashed
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1 on lower priority (second in list)
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000002; // Filter DST_IP == 127.0.0.2.
+		flt_rule_entry.rule.hashable = 0; // non hashed
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 3
+		flt_rule_entry.rule.hashable = 0; // non hashed
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+		unsigned short port;
+
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = ntohs(546);//DHCP Client Port
+		memcpy (&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = ntohs(547);//DHCP Server Port
+		memcpy (&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGolden_w_Status(m_sendBuffer, m_sendSize, rxBuff1, receivedSize))
+		{
+			printf("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize, receivedSize, rxBuff1) : IsCacheMiss(m_sendSize,receivedSize,rxBuff1);
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize, sentBufferSize, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize, sentBufferSize, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize, sentBufferSize, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize2, receivedSize2, rxBuff2) : IsCacheMiss(m_sendSize2,receivedSize2,rxBuff2);
+
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize3, receivedSize3, rxBuff3) : IsCacheMiss(m_sendSize3,receivedSize3,rxBuff3);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+};
+
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test064: IPV4 filtering test, hashed rule match, non hash doesn't match expect cache hit 	*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest064 : public IpaFilteringBlockTestFixture
+{
+public:
+
+	IpaFilteringBlockTest064()
+	{
+		m_name = "IpaFilteringBlockTest064";
+		m_description =
+		"Filtering block test 064 - Rules prioritization hashable vs non-hashable rule, only hashable matches the packets\
+		two identical packets are sent and should match the hashable rule, cache hit expected\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IP == (127.0.0.2 & 255.0.0.255)traffic goes to routing table 0 - non hashable\
+			All DST_IP == (127.0.0.1 & 255.0.0.255)traffic goes to routing table 1 - hashable\
+			All DST_IP == (192.169.1.2 & 255.0.0.255)traffic goes to routing table 2 - don't care for this specific test\
+		3. send three packets:\
+			DST_IP == 127.0.0.1 \
+			DST_IP == 127.0.0.1 \
+			DST_IP == 192.168.1.2";
+		m_minIPAHwType = IPA_HW_v3_0;
+		Register(*this);
+	}
+
+	bool Setup()
+	{
+		/* we want statuses on this test */
+		return IpaFilteringBlockTestFixture::Setup(true);
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass1, routing_table1.hdl);
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass2, routing_table2.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,3);
+		printf("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; //
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000002; // Filter DST_IP == 127.0.0.2.
+		flt_rule_entry.rule.hashable = 0; // non hashed
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1 on lower priority (second in list)
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		flt_rule_entry.rule.hashable = 1; // hashed
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 3
+		flt_rule_entry.rule.hashable = 0; // non hashed
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer2.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer2.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGolden_w_Status(m_sendBuffer, m_sendSize, rxBuff1, receivedSize))
+		{
+			printf("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize, receivedSize, rxBuff1) : IsCacheMiss(m_sendSize,receivedSize,rxBuff1);
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize, sentBufferSize, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize, sentBufferSize, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize, sentBufferSize, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ? 
+			IsCacheHit_v5_0(m_sendSize2, receivedSize2, rxBuff2) : IsCacheHit(m_sendSize2,receivedSize2,rxBuff2);
+
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize3, receivedSize3, rxBuff3) : IsCacheMiss(m_sendSize3,receivedSize3,rxBuff3);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test065: IPV4 filtering test, non hashable rule match with max priority vs hashable 		 	*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest065 : public IpaFilteringBlockTestFixture
+{
+public:
+
+	IpaFilteringBlockTest065()
+	{
+		m_name = "IpaFilteringBlockTest065";
+		m_description =
+		"Filtering block test 065 - Rules prioritization hashable vs non-hashable rule, both rules match the packets\
+		two identical packets are sent, non hashed with max priority should catch both\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IP == (127.0.0.1 & 255.0.0.255)traffic goes to routing table 0 - hashable\
+			All DST_IP == (127.0.0.1 & 255.0.0.255)traffic goes to routing table 1 - non hashable max prio\
+			All DST_IP == (192.169.1.2 & 255.0.0.255)traffic goes to routing table 2 - don't care for this specific test\
+		3. send three packets:\
+			DST_IP == 127.0.0.1 \
+			DST_IP == 127.0.0.1 \
+			DST_IP == 192.168.1.2";
+		m_minIPAHwType = IPA_HW_v3_0;
+		Register(*this);
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass1, routing_table1.hdl);
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass2, routing_table2.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,3);
+		printf("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; //
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		flt_rule_entry.rule.hashable = 1; // hashed
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1 on lower priority (second in list)
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		flt_rule_entry.rule.hashable = 0; // non hashed
+		flt_rule_entry.rule.max_prio = 1; // max prioirty, should overcome all other rules
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 3
+		flt_rule_entry.rule.hashable = 0; // non hashed
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer2.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer2.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGolden(m_sendBuffer, m_sendSize, rxBuff1, receivedSize))
+		{
+			printf("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize, sentBufferSize, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize, sentBufferSize, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize, sentBufferSize, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+		isSuccess &= CompareResultVsGolden(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+
+		isSuccess &= CompareResultVsGolden(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test066: IPV4 filtering test, hashed rule match, non hash doesn't match expect cache hit 	*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest066 : public IpaFilteringBlockTestFixture
+{
+public:
+	bool IsSecondTime;
+
+	IpaFilteringBlockTest066(): IsSecondTime(false)
+	{
+		m_name = "IpaFilteringBlockTest066";
+		m_description =
+		"Filtering block test 066 - Rules prioritization hashable vs non-hashable rule, only hashable matches the packets\
+		two identical packets are sent and should match the hashable rule, cache hit expected\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IP == (127.0.0.1 & 255.0.0.255)traffic goes to routing table 0 - hashable\
+			All DST_IP == (127.0.0.2 & 255.0.0.255)traffic goes to routing table 1 - non hashable\
+			All DST_IP == (192.169.1.2 & 255.0.0.255)traffic goes to routing table 2 - don't care for this specific test\
+		3. send three packets:\
+			DST_IP == 127.0.0.1 \
+			DST_IP == 127.0.0.1 \
+			DST_IP == 192.168.1.2";
+		m_minIPAHwType = IPA_HW_v3_0;
+		Register(*this);
+	}
+
+	bool Setup()
+	{
+		/* we want statuses on this test */
+		return IpaFilteringBlockTestFixture::Setup(true);
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass1, routing_table1.hdl);
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+		printf("route table %s has the handle %u\n", bypass2, routing_table2.hdl);
+
+		struct ipa_flt_rule_add flt_rule_entry;
+		if (!IsSecondTime) {
+			FilterTable0.Init(IPA_IP_v4, IPA_CLIENT_TEST_PROD, false, 3);
+			printf("FilterTable*.Init Completed Successfully..\n");
+			IsSecondTime = true;
+
+
+			// Configuring Filtering Rule No.0
+			FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+			flt_rule_entry.at_rear = true;
+			flt_rule_entry.flt_rule_hdl=-1; // return Value
+			flt_rule_entry.status = -1; // return value
+			flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+			flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+			flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; //
+			flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+			flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.2.
+			flt_rule_entry.rule.hashable = 1; // hashed
+			if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+			{
+				printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+				return false;
+			}
+
+			// Configuring Filtering Rule No.1 on lower priority (second in list)
+			flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+			flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+			flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000002; // Filter DST_IP == 127.0.0.1.
+			flt_rule_entry.rule.hashable = 0; // non hashed
+			if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+			{
+				printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+				return false;
+			}
+
+			// Configuring Filtering Rule No.2
+			flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl; //put here the handle corresponding to Routing Rule 3
+			flt_rule_entry.rule.hashable = 0; // non hashed
+			flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+			if (
+					((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+					!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				)
+			{
+				printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+				return false;
+			} else
+			{
+				printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+				printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+				printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+			}
+		} else {
+			printf("in the second time, just commit again\n");
+			if (!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())) {
+				printf("%s::Error Adding Rule to Filter Table, aborting...\n", __FUNCTION__);
+				return false;
+			}
+		}
+
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	bool RemoveLastRule()
+	{
+		struct ipa_ioc_del_flt_rule *pDeleteRule = (struct ipa_ioc_del_flt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_del_flt_rule) + sizeof(struct ipa_flt_rule_del));
+
+		pDeleteRule->commit = 1;
+		pDeleteRule->ip = IPA_IP_v4;
+		pDeleteRule->num_hdls = 1;
+		pDeleteRule->hdl[0].hdl = FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl;
+		pDeleteRule->hdl[0].status = FilterTable0.ReadRuleFromTable(2)->status;
+
+		if (!m_filtering.DeleteFilteringRule(pDeleteRule))
+		{
+			printf ("%s::Error Deleting Rule from Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		return true;
+	}
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGolden_w_Status(m_sendBuffer, m_sendSize, rxBuff1, receivedSize))
+		{
+			printf("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize, receivedSize, rxBuff1) : IsCacheMiss(m_sendSize,receivedSize,rxBuff1);
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize, sentBufferSize, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize, sentBufferSize, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize, sentBufferSize, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ? 
+			IsCacheHit_v5_0(m_sendSize2, receivedSize2, rxBuff2) : IsCacheHit(m_sendSize2,receivedSize2,rxBuff2);
+
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize3, receivedSize3, rxBuff3) : IsCacheMiss(m_sendSize3,receivedSize3,rxBuff3);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+
+	bool ReceiveAndCompareSpecial()
+	{
+		size_t receivedSize = 0;
+
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+
+		if (NULL == rxBuff1)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGolden_w_Status(m_sendBuffer, m_sendSize, rxBuff1, receivedSize))
+		{
+			printf("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize, receivedSize, rxBuff1) : IsCacheMiss(m_sendSize,receivedSize,rxBuff1);
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+		size_t j;
+
+		if ((3 * m_sendSize) > sentBufferSize)
+			printf("Failed to stringify sent packet. Buffer too small\n");
+		else
+			for(j = 0; j < m_sendSize; j++)
+				snprintf(&sentBuffer[3 * j], sentBufferSize - 3 * j,
+					" %02X", m_sendBuffer[j]);
+		if ((3 * receivedSize) > recievedBufferSize)
+			printf("Failed to stringify recieved packet. Buffer too small\n");
+		else
+			for(j = 0; j < receivedSize; j++)
+				snprintf(&recievedBuffer[3 * j], recievedBufferSize - 3 * j,
+					" %02X", rxBuff1[j]);
+		printf("Expected Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n",m_sendSize,sentBuffer,receivedSize,recievedBuffer);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+		delete[] rxBuff1;
+		return isSuccess;
+
+	}
+
+private:
+	IPAFilteringTable FilterTable0;
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test067: IPV4 filtering test, hash/cache invalidation on add test 										*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest067 : public IpaFilteringBlockTest066
+{
+public:
+	IpaFilteringBlockTest067()
+	{
+		m_name = "IpaFilteringBlockTest067";
+		m_description =
+		"Filtering block test 067 - this test first perfroms test 066 and then commits another rule\
+		another identical packet is sent: DST_IP == 127.0.0.1 and expected to get cache miss";
+		m_minIPAHwType = IPA_HW_v3_0;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		// Add the relevant filtering rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding filtering rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(m_IpaIPType);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		res = ModifyPackets();
+		if (false == res) {
+			printf("Failed to modify packets.\n");
+			return false;
+		}
+
+		// Send first packet
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		// untill here test 066 was run, now let's test the invalidation
+
+		// commit the same rules again, this should clear the cache
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding filtering rules.\n");
+			return false;
+		}
+
+		// send packet again
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)	{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// receive and verify that cache was missed
+		isSuccess = ReceiveAndCompareSpecial();
+
+		printf("Leaving %s, %s(), Returning %d\n",__FUNCTION__, __FILE__,isSuccess);
+
+		return isSuccess;
+	} // Run()
+
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test068: IPV4 filtering test, hash/cache invalidation on delete test 										*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest068 : public IpaFilteringBlockTest066
+{
+public:
+	IpaFilteringBlockTest068()
+	{
+		m_name = "IpaFilteringBlockTest068";
+		m_description =
+		"Filtering block test 068 - this test first perfroms test 066 and then removes last rule\
+		another identical packet is sent: DST_IP == 127.0.0.1 and expected to get cache miss";
+		m_minIPAHwType = IPA_HW_v3_0;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		// Add the relevant filtering rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding filtering rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(m_IpaIPType);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		res = ModifyPackets();
+		if (false == res) {
+			printf("Failed to modify packets.\n");
+			return false;
+		}
+
+		// Send first packet
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		// until here test 066 was run, now let's test the invalidation
+
+		// delete the last rule, this should clear the cache
+		res = RemoveLastRule();
+		if (false == res) {
+			printf("Failed removing filtering rules.\n");
+			return false;
+		}
+
+		// send packet again
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)	{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// receive and verify that cache was missed
+		isSuccess = ReceiveAndCompareSpecial();
+
+		printf("Leaving %s, %s(), Returning %d\n",__FUNCTION__, __FILE__,isSuccess);
+
+		return isSuccess;
+	} // Run()
+
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test070: IPV6 filtering test, non hashed priority higher than hashed priority				*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest070 : public IpaFilteringBlockTest060
+{
+public:
+
+	IpaFilteringBlockTest070()
+	{
+		m_name = "IpaFilteringBlockTest070";
+		m_description =
+		"Filtering block test 070 - Rules prioritization hashable vs non-hashable rule, both rules match the same packet but non hashable has higher priority\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IPv6 == 0x...AA traffic goes to routing table 0 - non hashable\
+			All DST_IPv6 == 0x...AA traffic goes to routing table 1 - hashable\
+			All DST_IPv6 == 0x...CC traffic goes to routing table 2 - non hashable - don't care for this specific test";
+		m_minIPAHwType = IPA_HW_v3_0;
+		m_IpaIPType = IPA_IP_v6;
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		uint32_t Hndl0, Hndl1, Hndl2;
+
+		if(!GetThreeIPv6BypassRoutingTables(&Hndl0,&Hndl1,&Hndl2)){
+			printf("failed to get three IPV6 routing tables!\n");
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v6,IPA_CLIENT_TEST_PROD,false,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl0; //put here the handle corresponding to Routing Rule 0
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x000000FF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0]		 = 0XFF020000; // Filter DST_IP
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1]		 = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2]      = 0x11223344;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677AA;
+		flt_rule_entry.rule.hashable = 0; // non hashable
+
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl1; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677AA;
+		flt_rule_entry.rule.hashable = 1; // hashable
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl2; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677CC;
+		flt_rule_entry.rule.hashable = 0; // non hashable
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool ModifyPackets()
+	{
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		m_sendBuffer3[DST_ADDR_LSB_OFFSET_IPV6] = 0xCC;
+		return true;
+	}// ModifyPacktes ()
+
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test071: IPV6 filtering test, hashed priority higher than non hashed priority + cache hit	*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest071: public IpaFilteringBlockTest061
+{
+public:
+
+	IpaFilteringBlockTest071()
+	{
+		m_name = "IpaFilteringBlockTest071";
+		m_description =
+		"Filtering block test 071 - Rules prioritization hashable vs non-hashable rule, both rules match the same packet but hashable has higher priority\
+		two identical packets are sent and should be catched by the hashable rule, second one should be hit the cache\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IPv6 == 0x...AA traffic goes to routing table 0 - hashable\
+			All DST_IPv6 == 0x...AA traffic goes to routing table 1 - non hashable\
+			All DST_IPv6 == 0x...CC traffic goes to routing table 2 - don't care for this specific test";
+		m_minIPAHwType = IPA_HW_v3_0;
+		m_IpaIPType = IPA_IP_v6;
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		uint32_t Hndl0, Hndl1, Hndl2;
+
+		if(!GetThreeIPv6BypassRoutingTables(&Hndl0,&Hndl1,&Hndl2)){
+			printf("failed to get three IPV6 routing tables!\n");
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v6,IPA_CLIENT_TEST_PROD,false,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl0; //put here the handle corresponding to Routing Rule 0
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x000000FF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0]		 = 0XFF020000; // Filter DST_IP
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1]		 = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2]      = 0x11223344;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677AA;
+		flt_rule_entry.rule.hashable = 1; // hashable
+
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl1; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677AA;
+		flt_rule_entry.rule.hashable = 0; // non hashable
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl2; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677CC;
+		flt_rule_entry.rule.hashable = 0; // non hashable
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool ModifyPackets()
+	{
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		// TODO: Add verification that we access only allocated addresses
+		// TODO: Fix this, doesn't match the Rule's Requirements
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		m_sendBuffer3[DST_ADDR_LSB_OFFSET_IPV6] = 0xCC;
+		return true;
+	}// ModifyPacktes ()
+
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test072: IPV6 filtering test, hashed rule match, non hash doesn't match expect cache miss	*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest072 : public IpaFilteringBlockTest062
+{
+public:
+
+	IpaFilteringBlockTest072()
+	{
+		m_name = "IpaFilteringBlockTest072";
+		m_description =
+		"Filtering block test 072 - Rules prioritization hashable vs non-hashable rule, only hashable matches the packets\
+		two packets with different tuple are sent and should match the hashable rule, no cache hit expected\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IPv6 == 0x...BB traffic goes to routing table 0 - non hashable\
+			All DST_IPv6 == 0x...AA traffic goes to routing table 1 - hashable\
+			All DST_IPv6 == 0x...CC traffic goes to routing table 2 - don't care for this specific test\
+		3. send three packets:\
+			DST_IP == 0x...AA port 546\
+			DST_IP == 0x...AA port 547\
+			DST_IP == 0x...CC";
+		m_minIPAHwType = IPA_HW_v3_0;
+		m_IpaIPType = IPA_IP_v6;
+
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		uint32_t Hndl0, Hndl1, Hndl2;
+
+		if(!GetThreeIPv6BypassRoutingTables(&Hndl0,&Hndl1,&Hndl2)){
+			printf("failed to get three IPV6 routing tables!\n");
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v6,IPA_CLIENT_TEST_PROD,false,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl0; //put here the handle corresponding to Routing Rule 0
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x000000FF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0]		 = 0XFF020000; // Filter DST_IP
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1]		 = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2]      = 0x11223344;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677BB;
+		flt_rule_entry.rule.hashable = 0; // non hashable
+
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl1; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677AA;
+		flt_rule_entry.rule.hashable = 1; // hashable
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl2; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677CC;
+		flt_rule_entry.rule.hashable = 0; // non hashable
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool ModifyPackets()
+	{
+
+		unsigned short port;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		port = ntohs(546);//DHCP Client Port
+		memcpy (&m_sendBuffer[IPV6_DST_PORT_OFFSET], &port, sizeof(port));
+
+		port = ntohs(547);//DHCP Client Port
+		memcpy (&m_sendBuffer2[IPV6_DST_PORT_OFFSET], &port, sizeof(port));
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+
+		m_sendBuffer3[DST_ADDR_LSB_OFFSET_IPV6] = 0xCC;
+		return true;
+	}// ModifyPacktes ()
+
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test073: IPV4 filtering test, hashed rule match, non hash doesn't match expect cache miss 	*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest073 : public IpaFilteringBlockTest063
+{
+public:
+
+	IpaFilteringBlockTest073()
+	{
+		m_name = "IpaFilteringBlockTest073";
+		m_description =
+		"Filtering block test 073 - Rules prioritization hashable vs non-hashable rule, only hashable matches the packets\
+		two packets with different tuple are sent and should match the hashable rule, no cache hit expected\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IPv6 == 0x...AA traffic goes to routing table 0 - hashable\
+			All DST_IPv6 == 0x...BB traffic goes to routing table 1 - non hashable\
+			All DST_IPv6 == 0x...CC traffic goes to routing table 2 - don't care for this specific test\
+		3. send three packets:\
+			DST_IP == 0x...AA port 546\
+			DST_IP == 0x...AA port 547\
+			DST_IP == 0x...CC";
+
+		m_minIPAHwType = IPA_HW_v3_0;
+		m_IpaIPType = IPA_IP_v6;
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		uint32_t Hndl0, Hndl1, Hndl2;
+
+		if(!GetThreeIPv6BypassRoutingTables(&Hndl0,&Hndl1,&Hndl2)){
+			printf("failed to get three IPV6 routing tables!\n");
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v6,IPA_CLIENT_TEST_PROD,false,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl0; //put here the handle corresponding to Routing Rule 0
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x000000FF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0]		 = 0XFF020000; // Filter DST_IP
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1]		 = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2]      = 0x11223344;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677AA;
+		flt_rule_entry.rule.hashable = 1; // hashable
+
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl1; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677BB;
+		flt_rule_entry.rule.hashable = 0; // non hashable
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl2; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677CC;
+		flt_rule_entry.rule.hashable = 0; // non hashable
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool ModifyPackets()
+	{
+
+		unsigned short port;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		port = ntohs(546);//DHCP Client Port
+		memcpy (&m_sendBuffer[IPV6_DST_PORT_OFFSET], &port, sizeof(port));
+
+		port = ntohs(547);//DHCP Client Port
+		memcpy (&m_sendBuffer2[IPV6_DST_PORT_OFFSET], &port, sizeof(port));
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+
+		m_sendBuffer3[DST_ADDR_LSB_OFFSET_IPV6] = 0xCC;
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test074: IPV6 filtering test, hashed rule match, non hash doesn't match expect cache hit 	*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest074 : public IpaFilteringBlockTest064
+{
+public:
+
+	IpaFilteringBlockTest074()
+	{
+		m_name = "IpaFilteringBlockTest074";
+		m_description =
+		"Filtering block test 074 - Rules prioritization hashable vs non-hashable rule, only hashable matches the packets\
+		two identical packets are sent and should match the hashable rule, cache hit expected\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IPv6 == 0x...BB traffic goes to routing table 0 - non hashable\
+			All DST_IPv6 == 0x...AA traffic goes to routing table 1 - hashable\
+			All DST_IPv6 == 0x...CC traffic goes to routing table 2 - don't care for this specific test\
+		3. send three packets:\
+			DST_IP == 0x...AA \
+			DST_IP == 0x...AA \
+			DST_IP == 0x...CC";
+		m_minIPAHwType = IPA_HW_v3_0;
+		m_IpaIPType = IPA_IP_v6;
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		uint32_t Hndl0, Hndl1, Hndl2;
+
+		if(!GetThreeIPv6BypassRoutingTables(&Hndl0,&Hndl1,&Hndl2)){
+			printf("failed to get three IPV6 routing tables!\n");
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v6,IPA_CLIENT_TEST_PROD,false,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl0; //put here the handle corresponding to Routing Rule 0
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x000000FF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0]		 = 0XFF020000; // Filter DST_IP
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1]		 = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2]      = 0x11223344;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677BB;
+		flt_rule_entry.rule.hashable = 0; // non hashable
+
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl1; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677AA;
+		flt_rule_entry.rule.hashable = 1; // hashable
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl2; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677CC;
+		flt_rule_entry.rule.hashable = 0; // non hashable
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool ModifyPackets()
+	{
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		m_sendBuffer3[DST_ADDR_LSB_OFFSET_IPV6] = 0xCC;
+		return true;
+	}// ModifyPacktes ()
+
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test075: IPV6 filtering test, non hashable rule match with max priority vs hashable 		 	*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest075 : public IpaFilteringBlockTest065
+{
+public:
+
+	IpaFilteringBlockTest075()
+	{
+		m_name = "IpaFilteringBlockTest075";
+		m_description =
+		"Filtering block test 075 - Rules prioritization hashable vs non-hashable rule, both rules match the packets\
+		two identical packets are sent, non hashed with max priority should catch both\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IPv6 == 0x...AA traffic goes to routing table 0 - hashable\
+			All DST_IPv6 == 0x...AA traffic goes to routing table 1 - non hashable max prio\
+			All DST_IPv6 == 0x...CC traffic goes to routing table 2 - don't care for this specific test\
+		3. send three packets:\
+			DST_IP == 0x...AA \
+			DST_IP == 0x...AA \
+			DST_IP == 0x...CC";
+		m_minIPAHwType = IPA_HW_v3_0;
+		m_IpaIPType = IPA_IP_v6;
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		uint32_t Hndl0, Hndl1, Hndl2;
+
+		if(!GetThreeIPv6BypassRoutingTables(&Hndl0,&Hndl1,&Hndl2)){
+			printf("failed to get three IPV6 routing tables!\n");
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v6,IPA_CLIENT_TEST_PROD,false,3);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl0; //put here the handle corresponding to Routing Rule 0
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x000000FF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0]		 = 0XFF020000; // Filter DST_IP
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1]		 = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2]      = 0x11223344;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677AA;
+		flt_rule_entry.rule.hashable = 1; // hashable
+
+		printf ("flt_rule_entry was set successfully, preparing for insertion....\n");
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl1; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677AA;
+		flt_rule_entry.rule.hashable = 0; // non hashable
+		flt_rule_entry.rule.max_prio = 1; // max priority
+
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=Hndl2; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3]      = 0X556677CC;
+		flt_rule_entry.rule.hashable = 0; // non hashable
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding RuleTable(2) to Filtering, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool ModifyPackets()
+	{
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		m_sendBuffer3[DST_ADDR_LSB_OFFSET_IPV6] = 0xCC;
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test076: IPV6 filtering test, hashed rule match, non hash doesn't match expect cache hit 	*/
+/*----------------------------------------------------------------------------------------------*/
+
+class IpaFilteringBlockTest076 : public IpaFilteringBlockTest066
+{
+public:
+
+	bool IsSecondTime;
+
+	IpaFilteringBlockTest076() :IsSecondTime(false)
+	{
+		m_name = "IpaFilteringBlockTest076";
+		m_description =
+		"Filtering block test 076 - Rules prioritization hashable vs non-hashable rule, only hashable matches the packets\
+		two identical packets are sent and should match the hashable rule, cache hit expected\
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit three filtering rules: (DST & Mask Match). \
+			All DST_IPv6 == 0x...AA traffic goes to routing table 0 - hashable\
+			All DST_IPv6 == 0x...BB traffic goes to routing table 1 - non hashable\
+			All DST_IPv6 == 0x...CC traffic goes to routing table 2 - don't care for this specific test\
+		3. send three packets:\
+			DST_IP == 0x...AA \
+			DST_IP == 0x...AA \
+			DST_IP == 0x...CC";
+		m_minIPAHwType = IPA_HW_v3_0;
+		m_IpaIPType = IPA_IP_v6;
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		uint32_t Hndl0, Hndl1, Hndl2;
+
+		if(!GetThreeIPv6BypassRoutingTables(&Hndl0,&Hndl1,&Hndl2)){
+			printf("failed to get three IPV6 routing tables!\n");
+			return false;
+		}
+
+		struct ipa_flt_rule_add flt_rule_entry;
+		if (!IsSecondTime) {
+			FilterTable0.Init(IPA_IP_v6, IPA_CLIENT_TEST_PROD, false, 3);
+			IsSecondTime = true;
+
+
+			// Configuring Filtering Rule No.0
+			FilterTable0.GeneratePresetRule(1, flt_rule_entry);
+			flt_rule_entry.at_rear = true;
+			flt_rule_entry.flt_rule_hdl = -1; // return Value
+			flt_rule_entry.status = -1; // return value
+			flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+			flt_rule_entry.rule.rt_tbl_hdl = Hndl0; //put here the handle corresponding to Routing Rule 0
+			flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;// Exact Match
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;// Exact Match
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;// Exact Match
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x000000FF;// Exact Match
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0XFF020000; // Filter DST_IP
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x11223344;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X556677AA;
+			flt_rule_entry.rule.hashable = 1; // hashable
+
+			printf("flt_rule_entry was set successfully, preparing for insertion....\n");
+
+			if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) {
+				printf("%s::Error Adding Rule to Filter Table, aborting...\n", __FUNCTION__);
+				return false;
+			}
+
+			// Configuring Filtering Rule No.1
+			flt_rule_entry.rule.rt_tbl_hdl = Hndl1; //put here the handle corresponding to Routing Rule 1
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X556677BB;
+			flt_rule_entry.rule.hashable = 0; // non hashable
+
+			if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) {
+				printf("%s::Error Adding Rule to Filter Table, aborting...\n", __FUNCTION__);
+				return false;
+			}
+
+			// Configuring Filtering Rule No.2
+			flt_rule_entry.rule.rt_tbl_hdl = Hndl2; //put here the handle corresponding to Routing Rule 2
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X556677CC;
+			flt_rule_entry.rule.hashable = 0; // non hashable
+
+			if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+				) {
+				printf("%s::Error Adding RuleTable(2) to Filtering, aborting...\n", __FUNCTION__);
+				return false;
+			} else {
+				printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(2)->status);
+			}
+		} else {
+			printf("in the second time, just commit again\n");
+			if (!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())) {
+				printf("%s::Error commiting rules second time, aborting...\n", __FUNCTION__);
+				return false;
+			}
+		}
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	bool RemoveLastRule()
+	{
+		struct ipa_ioc_del_flt_rule *pDeleteRule = (struct ipa_ioc_del_flt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_del_flt_rule) + sizeof(struct ipa_flt_rule_del));
+
+		pDeleteRule->commit = 1;
+		pDeleteRule->ip = IPA_IP_v6;
+		pDeleteRule->num_hdls = 1;
+		pDeleteRule->hdl[0].hdl = FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl;
+		pDeleteRule->hdl[0].status = FilterTable0.ReadRuleFromTable(2)->status;
+
+		if (!m_filtering.DeleteFilteringRule(pDeleteRule))
+		{
+			printf ("%s::Error Deleting Rule from Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		return true;
+	}
+
+	virtual bool ModifyPackets()
+	{
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		m_sendBuffer3[DST_ADDR_LSB_OFFSET_IPV6] = 0xCC;
+		return true;
+	}// ModifyPacktes ()
+
+private:
+	IPAFilteringTable FilterTable0;
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test077: IPV6 filtering test, hash/cache invalidation on add test 										*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest077 : public IpaFilteringBlockTest076
+{
+public:
+	IpaFilteringBlockTest077()
+	{
+		m_name = "IpaFilteringBlockTest077";
+		m_description =
+		"Filtering block test 077 - this test first perfroms test 076 and then commits another rule\
+		another identical packet is sent: DST_IP == 127.0.0.1 and expected to get cache miss";
+		m_minIPAHwType = IPA_HW_v3_0;
+		m_IpaIPType = IPA_IP_v6;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		// Add the relevant filtering rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding filtering rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(m_IpaIPType);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		res = ModifyPackets();
+		if (false == res) {
+			printf("Failed to modify packets.\n");
+			return false;
+		}
+
+		// Send first packet
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		// until here test 076 was run, now let's test the invalidation
+
+		// commit the same rules again, this should clear the cache
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding filtering rules.\n");
+			return false;
+		}
+
+		// send packet again
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)	{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// receive and verify that cache was missed
+		isSuccess = ReceiveAndCompareSpecial();
+
+		printf("Leaving %s, %s(), Returning %d\n",__FUNCTION__, __FILE__,isSuccess);
+
+		return isSuccess;
+	} // Run()
+
+};
+
+/*----------------------------------------------------------------------------------------------*/
+/* Test078: IPV6 filtering test, hash/cache invalidation on add test 										*/
+/*----------------------------------------------------------------------------------------------*/
+class IpaFilteringBlockTest078 : public IpaFilteringBlockTest076
+{
+public:
+	IpaFilteringBlockTest078()
+	{
+		m_name = "IpaFilteringBlockTest078";
+		m_description =
+		"Filtering block test 078 - this test first perfroms test 076 and then removes last rule\
+		another identical packet is sent: DST_IP == 127.0.0.1 and expected to get cache miss";
+		m_minIPAHwType = IPA_HW_v3_0;
+		m_IpaIPType = IPA_IP_v6;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		// Add the relevant filtering rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding filtering rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(m_IpaIPType);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		res = ModifyPackets();
+		if (false == res) {
+			printf("Failed to modify packets.\n");
+			return false;
+		}
+
+		// Send first packet
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		// until here test 076 was run, now let's test the invalidation
+
+		// delete the last rule, this should clear the cache
+		res = RemoveLastRule();
+		if (false == res) {
+			printf("Failed removing filtering rules.\n");
+			return false;
+		}
+
+		// send packet again
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)	{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// receive and verify that cache was missed
+		isSuccess = ReceiveAndCompareSpecial();
+
+		printf("Leaving %s, %s(), Returning %d\n",__FUNCTION__, __FILE__,isSuccess);
+
+		return isSuccess;
+	} // Run()
+
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test081: Type-of-service IP header field match  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest081 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest081()
+	{
+		m_name = "IpaFilteringBlockTest081";
+		m_description = " \
+		Filtering block test 081 - Source and Destination address and TOS exact match (End-Point specific Filtering Table, Insert all rules in a single commit) \
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules: \
+			All DST_IP == (127.0.0.1 & 255.0.0.255) and TOS == 0xFB traffic goes to routing table 0 \
+			All DST_IP == (192.168.1.1 & 255.0.0.255) and TOS == 0x10 traffic goes to routing table 1 \
+			All DST_IP == (192.168.1.2 & 255.0.0.255) and SRC_IP == (192.168.1.FF & 255.0.0.255) TOS == 0x25 traffic goes to routing table 2";
+		m_IpaIPType = IPA_IP_v4;
+		Register(*this);
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		printf("%s route table handle = %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+		printf("%s route table handle = %u\n", bypass1, routing_table1.hdl);
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+		printf("%s route table handle = %u\n", bypass2, routing_table2.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,3);
+		printf("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // out param
+		flt_rule_entry.status = -1; // out param
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR | IPA_FLT_TOS;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1
+		flt_rule_entry.rule.attrib.u.v4.tos = 0xFB;
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80101; // Filter DST_IP == 192.168.1.1
+		flt_rule_entry.rule.attrib.u.v4.tos = 0x10;
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_SRC_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2
+		flt_rule_entry.rule.attrib.u.v4.src_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.src_addr = 0xC0A801FF; // Filter DST_IP == 192.168.1.255
+		flt_rule_entry.rule.attrib.u.v4.tos = 0x25;
+
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl1=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl2=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+		address = ntohl(0x7F000001);//127.0.0.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		m_sendBuffer[IP4_TOS_FIELD_OFFSET] = 0xFB;
+
+		address = ntohl(0xC0A80101);//192.168.1.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		m_sendBuffer2[IP4_TOS_FIELD_OFFSET] = 0x10;
+
+		address = ntohl(0xC0A80102);//192.168.1.2
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		address = ntohl(0xC0A801FF);//192.168.1.255
+		memcpy(&m_sendBuffer3[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		m_sendBuffer3[IP4_TOS_FIELD_OFFSET] = 0x25;
+
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test082: Pure Ack packet match  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest082 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest082()
+	{
+		m_name = "IpaFilteringBlockTest082";
+		m_description = " \
+		Filtering block test 082 - Pure Ack packet match \
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules: \
+			All IS_PURE_ACK traffic goes to routing table 0 \
+			All DST_IP == (192.168.1.5 & 255.0.0.255) goes to routing table 1\
+			All other traffic goes to routing table 2";
+		m_IpaIPType = IPA_IP_v4;
+		m_minIPAHwType = IPA_HW_v4_5;
+		Register(*this);
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0,routing_table1,routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables (bypass0,bypass1,bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+		printf("%s route table handle = %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n",&routing_table1);
+			return false;
+		}
+		printf("%s route table handle = %u\n", bypass1, routing_table1.hdl);
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n",&routing_table2);
+			return false;
+		}
+		printf("%s route table handle = %u\n", bypass2, routing_table2.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4,IPA_CLIENT_TEST_PROD,false,3);
+		printf("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // out param
+		flt_rule_entry.status = -1; // out param
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_IS_PURE_ACK;
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table1.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80105; // Filter DST_IP == 192.168.1.5
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl=routing_table2.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = 0;
+		if (
+				((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+				!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			printf ("%s::Error Adding Rule to Filter Table, aborting...\n",__FUNCTION__);
+			return false;
+		} else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl1=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl2=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(2)->status);
+		}
+
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool LoadFiles(enum ipa_ip_type ip)
+	{
+		string fileName;
+
+		if (!LoadNoPayloadPacket(ip, m_sendBuffer, m_sendSize)) {
+			LOG_MSG_ERROR("Failed loading no payload Packet\n");
+			return false;
+		}
+		printf ("Loaded %zu Bytes to m_sendBuffer\n",m_sendSize);
+
+		if (!LoadNoPayloadPacket(ip, m_sendBuffer2, m_sendSize2)) {
+			LOG_MSG_ERROR("Failed loading no payload Packet\n");
+			return false;
+		}
+		printf ("Loaded %zu Bytes to m_sendBuffer2\n",m_sendSize2);
+
+		if (!LoadDefaultPacket(ip, m_extHdrType, m_sendBuffer3, m_sendSize3)) {
+			LOG_MSG_ERROR("Failed loading default Packet\n");
+			return false;
+		}
+		printf ("Loaded %zu Bytes to m_sendBuffer3\n",m_sendSize3);
+
+		return true;
+	}
+
+	virtual bool ModifyPackets()
+	{
+		int address;
+		if (
+				(NULL == m_sendBuffer) ||
+				(NULL == m_sendBuffer2) ||
+				(NULL == m_sendBuffer3)
+			)
+		{
+			printf ("Error : %s was called with NULL Buffers\n",__FUNCTION__);
+			return false;
+		}
+
+		m_sendBuffer[IPv4_TCP_FLAGS_OFFSET] |= TCP_ACK_FLAG_MASK;
+		address = ntohl(0xC0A80105);//192.168.1.5
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		address = ntohl(0xC0A80105);//192.168.1.5
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		m_sendBuffer3[IPv4_TCP_FLAGS_OFFSET] |= TCP_ACK_FLAG_MASK;
+		return true;
+	}// ModifyPacktes ()
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test090: VLAN ID filtering - IPv4  */
+/*---------------------------------------------------------------------------*/
+class IpaFilteringBlockTest090 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest090()
+	{
+		m_name = "IpaFilteringBlockTest090";
+		m_description = " \
+		Filtering block test 090 - VLAN ID packet match - IPv4 \
+		1. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit Three filtering rules: \
+			All VLAN ID == 5 goes to routing table 0 \
+			All VLAN ID == 6 goes to routing table 1\
+			All other traffic goes to routing table 2";
+		m_IpaIPType = IPA_IP_v4;
+		m_minIPAHwType = IPA_HW_v4_0;
+		Register(*this);
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0, routing_table1, routing_table2;
+
+		if (!CreateThreeIPv4BypassRoutingTables(bypass0, bypass1, bypass2)) {
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0)) {
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n", &routing_table0);
+			return false;
+		}
+		printf("%s route table handle = %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1)) {
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n", &routing_table1);
+			return false;
+		}
+		printf("%s route table handle = %u\n", bypass1, routing_table1.hdl);
+
+		routing_table2.ip = IPA_IP_v4;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2)) {
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%p) Failed.\n", &routing_table2);
+			return false;
+		}
+		printf("%s route table handle = %u\n", bypass2, routing_table2.hdl);
+
+		// note here we are using the VLAN pipe TEST2_PROD
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4, IPA_CLIENT_TEST2_PROD, false, 3);
+		printf("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1, flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1; // out param
+		flt_rule_entry.status = -1; // out param
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.retain_hdr = 1; // retain header so we can compare the VID
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_VLAN_ID;
+		flt_rule_entry.rule.attrib.vlan_id = 5; //filter all packets with vlan id == 5
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) {
+			printf("%s::Error Adding Rule to Filter Table, aborting...\n", __FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table1.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_VLAN_ID;
+		flt_rule_entry.rule.attrib.vlan_id = 6; //filter all packets with vlan id == 6
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) {
+			printf("%s::Error Adding Rule to Filter Table, aborting...\n", __FUNCTION__);
+			return false;
+		}
+
+		// Configuring Filtering Rule No.2
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table2.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = 0;
+		if (
+			((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			) {
+			printf("%s::Error Adding Rule to Filter Table, aborting...\n", __FUNCTION__);
+			return false;
+		} else {
+			printf("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(0)->status);
+			printf("flt rule hdl1=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(1)->status);
+			printf("flt rule hdl2=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(2)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(2)->status);
+		}
+
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool LoadFiles(enum ipa_ip_type ip)
+	{
+		string fileName;
+		if (!LoadDefault802_1Q(ip, m_sendBuffer, m_sendSize)) {
+			LOG_MSG_ERROR("Failed loading first VLAN Packet\n");
+			return false;
+		}
+		printf("Loaded %zu Bytes to m_sendBuffer\n", m_sendSize);
+
+		if (!LoadDefault802_1Q(ip, m_sendBuffer2, m_sendSize2)) {
+			LOG_MSG_ERROR("Failed loading second VLAN Packet\n");
+			return false;
+		}
+		printf("Loaded %zu Bytes to m_sendBuffer2\n", m_sendSize2);
+
+		if (!LoadDefault802_1Q(ip, m_sendBuffer3, m_sendSize3)) {
+			LOG_MSG_ERROR("Failed loading default Packet\n");
+			return false;
+		}
+		printf("Loaded %zu Bytes to m_sendBuffer3\n", m_sendSize3);
+
+		return true;
+	}
+
+	virtual bool ModifyPackets()
+	{
+		uint32_t vlan_802_1Q_tag;
+		if (
+			(NULL == m_sendBuffer) ||
+			(NULL == m_sendBuffer2) ||
+			(NULL == m_sendBuffer3)
+			) {
+			printf("Error : %s was called with NULL Buffers\n", __FUNCTION__);
+			return false;
+		}
+
+		vlan_802_1Q_tag = ntohl(0x81002005); //VLAN ID == 5
+		memcpy(&m_sendBuffer[TAG_802_1Q_OFFSET], &vlan_802_1Q_tag, sizeof(vlan_802_1Q_tag));
+
+		vlan_802_1Q_tag = ntohl(0x81002006); //VLAN ID == 6
+		memcpy(&m_sendBuffer2[TAG_802_1Q_OFFSET], &vlan_802_1Q_tag, sizeof(vlan_802_1Q_tag));
+
+		// default packet has vlan id == 3, assign it anyway
+		vlan_802_1Q_tag = ntohl(0x81002003); //VLAN ID == 3
+		memcpy(&m_sendBuffer3[TAG_802_1Q_OFFSET], &vlan_802_1Q_tag, sizeof(vlan_802_1Q_tag));
+		return true;
+	}// ModifyPacktes ()
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		// Add the relevant filtering rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding filtering rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(m_IpaIPType);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		res = ModifyPackets();
+		if (false == res) {
+			printf("Failed to modify packets.\n");
+			return false;
+		}
+
+		// Send first packet
+		isSuccess = m_producer2.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess) {
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		isSuccess = m_producer2.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess) {
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer2.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess) {
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		printf("Leaving %s, %s(), Returning %d\n", __FUNCTION__, __FILE__, isSuccess);
+
+		return isSuccess;
+	} // Run()
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test100: Cache LRU behavior test  */
+/*---------------------------------------------------------------------------*/
+#define CHACHE_ENTRIES 64
+#define CHACHE_PLUS_ONE (CHACHE_ENTRIES +1)
+class IpaFilteringBlockTest100 : public IpaFilteringBlockTestFixture
+{
+public:
+	IpaFilteringBlockTest100()
+	{
+		m_name = "IpaFilteringBlockTest100";
+		m_description = " \
+		Filtering block test 100 - Cache LRU behavior test \
+		1. Preload the cache by sending 64 packets for different connections \
+		2. Send another packet for 65th connection \
+		3. Send packets for first 64 connections \
+		4. Verify that 1st connection’s entry was reclaimed";
+		m_IpaIPType = IPA_IP_v4;
+		m_minIPAHwType = IPA_HW_v4_0;
+		Register(*this);
+	}
+
+	bool Setup()
+	{
+		/* we want statuses on this test */
+		return IpaFilteringBlockTestFixture::Setup(true);
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		int i;
+		struct ipa_ioc_get_rt_tbl routing_table0;
+		const char bypass0[20] = "Bypass0";
+
+		if (!CreateBypassRoutingTable(&m_routing,
+									  m_IpaIPType,
+									  bypass0,
+									  IPA_CLIENT_TEST2_CONS,
+									  0,
+									  &routing_table0.hdl)) {
+			LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+			return false;
+		}
+
+		routing_table0.ip = m_IpaIPType;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n",&routing_table0);
+			return false;
+		}
+
+		printf("Creating Bypass Routing Table completed successfully\n");
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4, IPA_CLIENT_TEST_PROD, false, CHACHE_PLUS_ONE);
+		printf("FilterTable*.Init Completed Successfully..\n");
+
+		FilterTable0.GeneratePresetRule(1, flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		flt_rule_entry.rule.hashable = 1;
+
+		for (i = 0; i < CHACHE_PLUS_ONE; i++) {
+			// Configuring Filtering Rule No.i
+			flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xC0A80101 + i; // Filter DST_IP == 192.168.1.(1+i).
+			if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) {
+				printf("%s::Error Adding Rule to Filter Table, aborting...\n", __FUNCTION__);
+				return false;
+			}
+		}
+
+		if (!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable()))
+		{
+			printf ("%s::Error Adding RuleTable(%d) to Filtering, aborting...\n", __FUNCTION__, i);
+			return false;
+		} else {
+			for (i = 0; i < CHACHE_PLUS_ONE; i++) {
+				printf("flt rule hdl=0x%x, status=0x%x\n",
+					   FilterTable0.ReadRuleFromTable(i)->flt_rule_hdl,
+					   FilterTable0.ReadRuleFromTable(i)->status);
+			}
+		}
+
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool ModifyPackets() {
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		// Add the relevant filtering rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding filtering rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(m_IpaIPType);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send the first CHACHE_ENTRIES packets
+		// Receive packets and compare results
+		// All rules should be cache miss
+		for (int i = 0; i < CHACHE_ENTRIES; i++) {
+			res = __ModifyPackets(i);
+			if (false == res) {
+				printf("Failed to modify packets.\n");
+				return false;
+			}
+
+			isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+			if (false == isSuccess)
+			{
+				printf("SendData failure.\n");
+				return false;
+			}
+
+			isSuccess = ReceivePacketAndCompareFrom(m_consumer, m_sendBuffer, m_sendSize, false);
+			if (false == isSuccess)	{
+				printf("%s:%d: ReceivePacketAndCompareFrom failure.\n", __FUNCTION__, __LINE__);
+				return false;
+			}
+		}
+
+		// Send again the first CHACHE_ENTRIES packets
+		// Receive packets and compare results
+		// All rules should be cache hit
+		for (int i = 0; i < CHACHE_ENTRIES; i++) {
+			res = __ModifyPackets(i);
+			if (false == res) {
+				printf("Failed to modify packets.\n");
+				return false;
+			}
+
+			isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+			if (false == isSuccess)
+			{
+				printf("SendData failure.\n");
+				return false;
+			}
+
+			isSuccess = ReceivePacketAndCompareFrom(m_consumer, m_sendBuffer, m_sendSize, true);
+			if (false == isSuccess)	{
+				printf("%s:%d: ReceivePacketAndCompareFrom failure.\n", __FUNCTION__, __LINE__);
+				return false;
+			}
+		}
+
+		// Send a packet to a new filter entry, this should trigger the LRU clear
+		res = __ModifyPackets(CHACHE_ENTRIES);
+		if (false == res) {
+			printf("Failed to modify packets.\n");
+			return false;
+		}
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)	{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// receive and verify that cache was missed
+		isSuccess = ReceivePacketAndCompareFrom(m_consumer, m_sendBuffer, m_sendSize, false);
+		if (false == isSuccess)	{
+			printf("%s:%d: ReceivePacketAndCompareFrom failure.\n", __FUNCTION__, __LINE__);
+			return false;
+		}
+
+		// send the first packet again
+		res = __ModifyPackets(0);
+		if (false == res) {
+			printf("Failed to modify packets.\n");
+			return false;
+		}
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)	{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// receive and verify that cache was missed
+		isSuccess = ReceivePacketAndCompareFrom(m_consumer, m_sendBuffer, m_sendSize, false);
+		if (false == isSuccess)	{
+			printf("%s:%d: ReceivePacketAndCompareFrom failure.\n", __FUNCTION__, __LINE__);
+			return false;
+		}
+
+		printf("Leaving %s, %s(), Returning %d\n",__FUNCTION__, __FILE__, isSuccess);
+
+		return isSuccess;
+	} // Run()
+
+private:
+	bool __ModifyPackets(int i)
+	{
+		int address;
+		if (NULL == m_sendBuffer)
+		{
+			printf ("Error : %s was called with NULL Buffer\n", __FUNCTION__);
+			return false;
+		}
+
+		address = ntohl(0xC0A80101 + i); // 192.168.1.(1+i)
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+
+		return true;
+	}
+
+};
+
+static class IpaFilteringBlockTest001 ipaFilteringBlockTest001;//Global Filtering Test
+static class IpaFilteringBlockTest002 ipaFilteringBlockTest002;//Global Filtering Test
+static class IpaFilteringBlockTest003 ipaFilteringBlockTest003;//Global Filtering Test
+static class IpaFilteringBlockTest004 ipaFilteringBlockTest004;//Global Filtering Test
+static class IpaFilteringBlockTest005 ipaFilteringBlockTest005;//Global Filtering Test
+static class IpaFilteringBlockTest006 ipaFilteringBlockTest006;//Global Filtering Test
+static class IpaFilteringBlockTest007 ipaFilteringBlockTest007;//Global Filtering Test
+static class IpaFilteringBlockTest008 ipaFilteringBlockTest008;//Global Filtering Test
+static class IpaFilteringBlockTest009 ipaFilteringBlockTest009;//Global Filtering Test
+static class IpaFilteringBlockTest010 ipaFilteringBlockTest010;//Global Filtering Test
+
+static class IpaFilteringBlockTest021 ipaFilteringBlockTest021;//End point Specific Filtering Table
+static class IpaFilteringBlockTest022 ipaFilteringBlockTest022;//End point Specific Filtering Table
+static class IpaFilteringBlockTest023 ipaFilteringBlockTest023;//End point Specific Filtering Table
+static class IpaFilteringBlockTest024 ipaFilteringBlockTest024;//End point Specific Filtering Table
+static class IpaFilteringBlockTest025 ipaFilteringBlockTest025;//End point Specific Filtering Table
+static class IpaFilteringBlockTest026 ipaFilteringBlockTest026;//End point Specific Filtering Table
+static class IpaFilteringBlockTest027 ipaFilteringBlockTest027;//End point Specific Filtering Table
+static class IpaFilteringBlockTest028 ipaFilteringBlockTest028;//End point Specific Filtering Table
+static class IpaFilteringBlockTest029 ipaFilteringBlockTest029;//End point Specific Filtering Table
+static class IpaFilteringBlockTest030 ipaFilteringBlockTest030;//End point Specific Filtering Table
+static class IpaFilteringBlockTest031 ipaFilteringBlockTest031;//End point Specific Filtering Table
+
+static class IpaFilteringBlockTest050 ipaFilteringBlockTest050;// IPv6 Test, Global Filtering Table
+static class IpaFilteringBlockTest051 ipaFilteringBlockTest051;// IPv6 Test, End point Specific Filtering Table
+static class IpaFilteringBlockTest052 ipaFilteringBlockTest052;// IPv6 Test, Global Filtering Table
+static class IpaFilteringBlockTest053 ipaFilteringBlockTest053;// IPv6 Test, End point Specific Filtering Table
+static class IpaFilteringBlockTest054 ipaFilteringBlockTest054;// IPv6 Test, End point Specific Filtering Table
+
+static class IpaFilteringBlockTest060 ipaFilteringBlockTest060; // Hashed non hashed tests IPv4
+static class IpaFilteringBlockTest061 ipaFilteringBlockTest061; // Hashed non hashed tests IPv4
+static class IpaFilteringBlockTest062 ipaFilteringBlockTest062; // Hashed non hashed tests IPv4
+static class IpaFilteringBlockTest063 ipaFilteringBlockTest063; // Hashed non hashed tests IPv4
+static class IpaFilteringBlockTest064 ipaFilteringBlockTest064; // Hashed non hashed tests IPv4
+static class IpaFilteringBlockTest065 ipaFilteringBlockTest065; // Hashed non hashed tests IPv4
+static class IpaFilteringBlockTest066 ipaFilteringBlockTest066; // Hashed non hashed tests IPv4
+static class IpaFilteringBlockTest067 ipaFilteringBlockTest067; // Cache/Hash invalidation on add test
+static class IpaFilteringBlockTest068 ipaFilteringBlockTest068; // Cache/Hash invalidation on delete test
+
+static class IpaFilteringBlockTest070 ipaFilteringBlockTest070; // Hashed non hashed tests IPV6
+static class IpaFilteringBlockTest071 ipaFilteringBlockTest071; // Hashed non hashed tests IPV6
+static class IpaFilteringBlockTest072 ipaFilteringBlockTest072; // Hashed non hashed tests IPV6
+static class IpaFilteringBlockTest073 ipaFilteringBlockTest073; // Hashed non hashed tests IPV6
+static class IpaFilteringBlockTest074 ipaFilteringBlockTest074; // Hashed non hashed tests IPV6
+static class IpaFilteringBlockTest075 ipaFilteringBlockTest075; // Hashed non hashed tests IPV6
+static class IpaFilteringBlockTest076 ipaFilteringBlockTest076; // Hashed non hashed tests IPV6
+static class IpaFilteringBlockTest077 ipaFilteringBlockTest077; // Cache/Hash invalidation on add test
+static class IpaFilteringBlockTest078 ipaFilteringBlockTest078; // Cache/Hash invalidation on delete test
+
+static class IpaFilteringBlockTest081 ipaFilteringBlockTest081; // Type-of-service Filter rule test
+static class IpaFilteringBlockTest082 ipaFilteringBlockTest082; // IPv4 Pure Ack Filter rule test
+
+static class IpaFilteringBlockTest090 ipaFilteringBlockTest090; // VLAN filtering test IPv4
+
+static class IpaFilteringBlockTest100 ipaFilteringBlockTest100; // Cache LRU behavior test
+

+ 178 - 0
kernel-tests/HeaderInsertion.cpp

@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "HeaderInsertion.h"
+
+/*All interaction through the driver are
+ * made through this inode.
+ */
+static const char* DEVICE_NAME = "/dev/ipa";
+
+#define LOG_IOCTL_RETURN_VALUE(nRetVal) \
+		printf("%s()- %s\n", __func__, \
+		(-1 == nRetVal) ? "Fail" : "Success");
+
+HeaderInsertion::HeaderInsertion()
+{
+	m_fd = open(DEVICE_NAME, O_RDWR);
+	if (-1 == m_fd)
+	{
+		printf(
+			"Failed to open %s in HeaderInsertion test application constructor.\n",
+			DEVICE_NAME);
+	}
+}
+
+HeaderInsertion::~HeaderInsertion()
+{
+	if (-1 != m_fd)
+	{
+		close(m_fd);
+	}
+}
+
+bool HeaderInsertion::DeviceNodeIsOpened()
+{
+	return (-1 != m_fd);
+}
+
+bool HeaderInsertion::AddHeader(struct ipa_ioc_add_hdr *pHeaderTableToAdd)
+{
+	int nRetVal = 0;
+	/*call the Driver ioctl in order to add header*/
+	nRetVal = ioctl(m_fd, IPA_IOC_ADD_HDR, pHeaderTableToAdd);
+	LOG_IOCTL_RETURN_VALUE(nRetVal);
+	return (-1 != nRetVal);
+}
+
+bool HeaderInsertion::DeleteHeader(struct ipa_ioc_del_hdr *pHeaderTableToDelete)
+{
+	int nRetVal = 0;
+	/*call the Driver ioctl in order to remove header*/
+	nRetVal = ioctl(m_fd, IPA_IOC_DEL_HDR , pHeaderTableToDelete);
+	LOG_IOCTL_RETURN_VALUE(nRetVal);
+	return (-1 != nRetVal);
+}
+
+bool HeaderInsertion::AddProcCtx(struct ipa_ioc_add_hdr_proc_ctx *procCtxTable)
+{
+	int retval = 0;
+
+	retval = ioctl(m_fd, IPA_IOC_ADD_HDR_PROC_CTX, procCtxTable);
+	if (retval) {
+		printf("%s(), failed adding ProcCtx rule table %p\n", __FUNCTION__, procCtxTable);
+		return false;
+	}
+
+	printf("%s(), Added ProcCtx rule to table %p\n", __FUNCTION__, procCtxTable);
+	return true;
+}
+
+bool HeaderInsertion::DeleteProcCtx(struct ipa_ioc_del_hdr_proc_ctx *procCtxTable)
+{
+	int retval = 0;
+
+	retval = ioctl(m_fd, IPA_IOC_DEL_HDR_PROC_CTX, procCtxTable);
+	if (retval) {
+		printf("%s(), failed deleting ProcCtx rule in table %p\n", __FUNCTION__, procCtxTable);
+		return false;
+	}
+
+	printf("%s(), Deleted ProcCtx rule in table %p\n", __FUNCTION__, procCtxTable);
+	return true;
+}
+
+bool HeaderInsertion::Commit()
+{
+	int nRetVal = 0;
+	nRetVal = ioctl(m_fd, IPA_IOC_COMMIT_HDR);
+	LOG_IOCTL_RETURN_VALUE(nRetVal);
+	return true;
+}
+
+bool HeaderInsertion::Reset()
+{
+	int nRetVal = 0;
+
+	nRetVal = ioctl(m_fd, IPA_IOC_RESET_HDR);
+	nRetVal |= ioctl(m_fd, IPA_IOC_COMMIT_HDR);
+	LOG_IOCTL_RETURN_VALUE(nRetVal);
+	return true;
+}
+
+bool HeaderInsertion::GetHeaderHandle(struct ipa_ioc_get_hdr *pHeaderStruct)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened())
+		return false;
+
+	retval = ioctl(m_fd, IPA_IOC_GET_HDR, pHeaderStruct);
+	if (retval) {
+		printf(
+		"%s(), IPA_IOC_GET_HDR ioctl failed, routingTable =0x%p, retval=0x%x.\n"
+		, __func__,
+		pHeaderStruct,
+		retval);
+		return false;
+	}
+
+	printf(
+	"%s(), IPA_IOC_GET_HDR ioctl issued to IPA header insertion block.\n",
+	__func__);
+	return true;
+}
+
+bool HeaderInsertion::CopyHeader(struct ipa_ioc_copy_hdr *pCopyHeaderStruct)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened())
+		return false;
+
+	retval = ioctl(m_fd, IPA_IOC_COPY_HDR, pCopyHeaderStruct);
+	if (retval) {
+		printf(
+		"%s(), IPA_IOC_COPY_HDR ioctl failed, retval=0x%x.\n",
+		__func__,
+		retval);
+		return false;
+	}
+
+	printf(
+	"%s(), IPA_IOC_COPY_HDR ioctl issued to IPA header insertion block.\n",
+	__func__);
+	return true;
+}
+

+ 59 - 0
kernel-tests/HeaderInsertion.h

@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HEADER_INSERTION_H_
+#define HEADER_INSERTION_H_
+
+#include <stdint.h>
+#include "linux/msm_ipa.h"
+
+class HeaderInsertion
+{
+private:
+	int m_fd;
+
+public:
+	bool AddHeader(struct ipa_ioc_add_hdr *pHeaderTable);
+	bool DeleteHeader(struct ipa_ioc_del_hdr *pHeaderTable);
+	bool GetHeaderHandle(struct ipa_ioc_get_hdr *pHeaderStruct);
+	bool CopyHeader(struct ipa_ioc_copy_hdr *pCopyHeaderStruct);
+
+	// Processing context
+	bool AddProcCtx(struct ipa_ioc_add_hdr_proc_ctx *procCtxTable);
+	bool DeleteProcCtx(struct ipa_ioc_del_hdr_proc_ctx *procCtxTable);
+
+	bool Commit();
+	bool Reset();
+
+	HeaderInsertion();
+	~HeaderInsertion();
+	bool DeviceNodeIsOpened();
+};
+
+#endif

+ 875 - 0
kernel-tests/HeaderInsertionTests.cpp

@@ -0,0 +1,875 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "RoutingDriverWrapper.h"
+#include "HeaderInsertion.h"
+#include "Filtering.h"
+#include "IPAFilteringTable.h"
+#include "hton.h" // for htonl
+#include "TestsUtils.h"
+#include <string.h>
+
+#define IPV4_DST_ADDR_OFFSET (16)
+
+class IPAHeaderInsertionTestFixture: public TestBase {
+public:
+
+	IPAHeaderInsertionTestFixture() : m_uBufferSize(0)
+	{
+		memset(m_aBuffer, 0, sizeof(m_aBuffer));
+		m_testSuiteName.push_back("Insertion");
+	}
+
+	virtual bool AddRules() = 0;
+	virtual bool ModifyPackets() = 0;
+	virtual bool TestLogic() = 0;
+
+	bool Setup()
+	{
+
+		ConfigureScenario(PHASE_FIVE_TEST_CONFIGURATION);
+
+		m_producer.Open(INTERFACE0_TO_IPA_DATA_PATH,
+				INTERFACE0_FROM_IPA_DATA_PATH);
+		m_Consumer1.Open(INTERFACE1_TO_IPA_DATA_PATH,
+				INTERFACE1_FROM_IPA_DATA_PATH);
+		m_Consumer2.Open(INTERFACE2_TO_IPA_DATA_PATH,
+				INTERFACE2_FROM_IPA_DATA_PATH);
+		m_Consumer3.Open(INTERFACE3_TO_IPA_DATA_PATH,
+				INTERFACE3_FROM_IPA_DATA_PATH);
+
+		if (!m_Routing.DeviceNodeIsOpened()) {
+			LOG_MSG_ERROR(
+					"Routing block is not ready for immediate commands!\n");
+			return false;
+		}
+		if (!m_Filtering.DeviceNodeIsOpened()) {
+			LOG_MSG_ERROR(
+					"Filtering block is not ready for immediate commands!\n");
+			return false;
+		}
+		if (!m_HeaderInsertion.DeviceNodeIsOpened())
+		{
+			LOG_MSG_ERROR("Header Insertion block is not ready for immediate commands!\n");
+			return false;
+		}
+		m_HeaderInsertion.Reset();// resetting this component will reset both Routing and Filtering tables.
+
+		return true;
+	} // Setup()
+
+	bool Run()
+	{
+		m_uBufferSize = BUFF_MAX_SIZE;
+		LOG_MSG_STACK("Entering Function");
+
+		// Add the relevant filtering rules
+		if (!AddRules()) {
+			LOG_MSG_ERROR("Failed adding filtering rules.");
+			return false;
+		}
+		// Load input data (IP packet) from file
+		if (!LoadDefaultPacket(m_eIP, m_aBuffer, m_uBufferSize)) {
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		if (!ModifyPackets()) {
+			LOG_MSG_ERROR("Failed to modify packets.");
+			return false;
+		}
+		if (!TestLogic()) {
+			LOG_MSG_ERROR("Test failed, Input and expected output mismatch.");
+			return false;
+		}
+
+		LOG_MSG_STACK("Leaving Function (Returning True)");
+		return true;
+	} // Run()
+
+	bool Teardown()
+	{
+		m_HeaderInsertion.Reset();// resetting this component will reset both Routing and Filtering tables.
+		m_producer.Close();
+		m_Consumer1.Close();
+		m_Consumer2.Close();
+		m_Consumer3.Close();
+		return true;
+	} // Teardown()
+
+	~IPAHeaderInsertionTestFixture() {}
+
+	static RoutingDriverWrapper m_Routing;
+	static Filtering m_Filtering;
+	static HeaderInsertion m_HeaderInsertion;
+	InterfaceAbstraction m_producer;
+	InterfaceAbstraction m_Consumer1;
+	InterfaceAbstraction m_Consumer2;
+	InterfaceAbstraction m_Consumer3;
+
+protected:
+	static const size_t BUFF_MAX_SIZE = 1024;
+	static const uint8_t MAX_HEADER_SIZE = 64; // 64Bytes - Max Header Length
+	enum ipa_ip_type m_eIP;
+	uint8_t m_aBuffer[BUFF_MAX_SIZE]; // Input file \ IP packet
+	size_t m_uBufferSize;
+
+};
+RoutingDriverWrapper IPAHeaderInsertionTestFixture::m_Routing;
+Filtering IPAHeaderInsertionTestFixture::m_Filtering;
+HeaderInsertion IPAHeaderInsertionTestFixture::m_HeaderInsertion;
+
+//---------------------------------------------------------------------------/
+// Test002: Test that 802.3 header was inserted Correctly                        /
+//---------------------------------------------------------------------------/
+class IPAHeaderInsertionTest001: public IPAHeaderInsertionTestFixture {
+public:
+	IPAHeaderInsertionTest001() {
+		m_name = "IPAHeaderInsertionTest001";
+		m_description =
+		"Header Insertion Test 001 - Test RMNet Header Insertion\
+		1. Generate and commit RMNet.3 header Insertion \
+		2. Generate and commit routing table containing bypass rule. \
+		3. Generate and commit bypass filtering rule. \
+		4. Send a packet, and verify that the RMNet.3 Header was inserted correctly.";
+		Register(*this);
+		uint8_t aRMNetHeader[6] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
+		m_nHeadertoAddSize = sizeof(aRMNetHeader);
+		memcpy(m_aHeadertoAdd, aRMNetHeader, m_nHeadertoAddSize);
+	}
+
+	// Test Description:
+	// 1. Generate and commit single bypass routing table.
+	virtual bool AddRules() {
+		m_eIP = IPA_IP_v4;
+		const char bypass0[20] = "Bypass0";
+		struct ipa_ioc_get_rt_tbl sRoutingTable;
+		bool bRetVal = true;
+		struct ipa_ioc_get_hdr sRetHeader;
+		IPAFilteringTable cFilterTable;
+		struct ipa_flt_rule_add sFilterRuleEntry;
+		uint32_t nRTTableHdl=0;
+		memset(&sRoutingTable, 0, sizeof(sRoutingTable));
+		memset(&sRetHeader, 0, sizeof(sRetHeader));
+		strlcpy(sRetHeader.name, "IEEE802_3", sizeof(sRetHeader.name));
+
+		LOG_MSG_STACK("Entering Function");
+		// Create Header:
+		// Allocate Memory, populate it, and add in to the Header Insertion.
+		struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+		pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+				sizeof(struct ipa_ioc_add_hdr)
+						+ 1 * sizeof(struct ipa_hdr_add));
+		if (!pHeaderDescriptor) {
+			LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+			bRetVal = false;
+			goto bail;
+		}
+		pHeaderDescriptor->commit = true;
+		pHeaderDescriptor->num_hdrs = 1;
+		strlcpy(pHeaderDescriptor->hdr[0].name, sRetHeader.name, sizeof(pHeaderDescriptor->hdr[0].name));
+		memcpy(pHeaderDescriptor->hdr[0].hdr, m_aHeadertoAdd,
+				m_nHeadertoAddSize); //Header's Data
+		pHeaderDescriptor->hdr[0].hdr_len = m_nHeadertoAddSize;
+		pHeaderDescriptor->hdr[0].hdr_hdl = -1; //Return Value
+		pHeaderDescriptor->hdr[0].is_partial = false;
+		pHeaderDescriptor->hdr[0].status = -1; // Return Parameter
+		strlcpy(sRetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sRetHeader.name));
+
+		if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+		{
+			LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+		if (!m_HeaderInsertion.GetHeaderHandle(&sRetHeader))
+		{
+			LOG_MSG_ERROR(" Failed");
+			bRetVal = false;
+			goto bail;
+		}
+		if (!CreateBypassRoutingTable(&m_Routing, m_eIP, bypass0, IPA_CLIENT_TEST2_CONS,
+				sRetHeader.hdl,&nRTTableHdl)) {
+			LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+		}
+		LOG_MSG_INFO("CreateBypassRoutingTable completed successfully");
+		sRoutingTable.ip = m_eIP;
+		strlcpy(sRoutingTable.name, bypass0, sizeof(sRoutingTable.name));
+		if (!m_Routing.GetRoutingTable(&sRoutingTable)) {
+			LOG_MSG_ERROR(
+					"m_routing.GetRoutingTable(&sRoutingTable=0x%p) Failed.", &sRoutingTable);
+			bRetVal = false;
+			goto bail;
+		}
+		// Creating Filtering Rules
+		cFilterTable.Init(m_eIP,IPA_CLIENT_TEST_PROD,false,1);
+		LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+		// Configuring Filtering Rule No.1
+		cFilterTable.GeneratePresetRule(0,sFilterRuleEntry);
+		sFilterRuleEntry.at_rear = true;
+		sFilterRuleEntry.flt_rule_hdl = -1; // return Value
+		sFilterRuleEntry.status = -1; // return value
+		sFilterRuleEntry.rule.action = IPA_PASS_TO_ROUTING;
+		sFilterRuleEntry.rule.rt_tbl_hdl = nRTTableHdl; //put here the handle corresponding to Routing Rule 1
+		if (
+				((uint8_t)-1 == cFilterTable.AddRuleToTable(sFilterRuleEntry)) ||
+				!m_Filtering.AddFilteringRule(cFilterTable.GetFilteringTable())
+				)
+		{
+			LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+			bRetVal = false;
+			goto bail;
+		} else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable.ReadRuleFromTable(0)->status);
+		}
+
+	bail:
+		Free(pHeaderDescriptor);
+		LOG_MSG_STACK(
+				"Leaving Function (Returning %s)", bRetVal?"True":"False");
+		return bRetVal;
+	} // AddRules()
+
+	virtual bool ModifyPackets() {
+		// This test doesn't modify the original IP Packet.
+		return true;
+	} // ModifyPacktes ()
+
+	virtual bool TestLogic() {
+		memset(m_aExpectedBuffer, 0, sizeof(m_aExpectedBuffer));
+		m_aExpectedBufSize = 0;
+
+		memcpy(m_aExpectedBuffer, m_aHeadertoAdd, m_nHeadertoAddSize);
+		memcpy(m_aExpectedBuffer+m_nHeadertoAddSize,m_aBuffer,m_uBufferSize);
+		m_aExpectedBufSize = m_nHeadertoAddSize + m_uBufferSize;
+		if (!SendReceiveAndCompare(&m_producer, m_aBuffer, m_uBufferSize,
+				&m_Consumer1, m_aExpectedBuffer, m_aExpectedBufSize)) {
+			LOG_MSG_ERROR("SendReceiveAndCompare failed.");
+			return false;
+		}
+		return true;
+	}
+private:
+	uint8_t m_aExpectedBuffer[BUFF_MAX_SIZE]; // Input file / IP packet
+	size_t m_aExpectedBufSize;
+	uint8_t m_aHeadertoAdd[MAX_HEADER_SIZE];
+	size_t m_nHeadertoAddSize;
+};
+
+//---------------------------------------------------------------------------/
+// Test002: Test that 802.3 header was inserted Correctly                        /
+//---------------------------------------------------------------------------/
+class IPAHeaderInsertionTest002: public IPAHeaderInsertionTestFixture {
+public:
+	IPAHeaderInsertionTest002() {
+		m_name = "IPAHeaderInsertionTest002";
+		m_description =
+		"Header Insertion Test 002 - Test IEEE802.3 Header Insertion\
+		1. Generate and commit IEEE802.3 header Insertion \
+		2. Generate and commit routing table containing bypass rule. \
+		3. Generate and commit bypass filtering rule. \
+		4. Send a packet, and verify that the IEEE802.3 Header was inserted correctly \
+		   and that the header Length was updated as well";
+		Register(*this);
+		uint8_t aIEEE802_3Header[22] = { 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+				0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0x00, 0x46, 0xAE, 0xAF, 0xB0,// the correct size (00 46) is inserted here.
+				0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6 };
+		m_nHeadertoAddSize = sizeof(aIEEE802_3Header);
+		memcpy(m_aHeadertoAdd, aIEEE802_3Header, m_nHeadertoAddSize);
+	}
+
+	// Test Description:
+	// 1. Generate and commit single bypass routing table.
+	virtual bool AddRules() {
+		m_eIP = IPA_IP_v4;
+		const char bypass0[20] = "Bypass0";
+		struct ipa_ioc_get_rt_tbl sRoutingTable;
+		bool bRetVal = true;
+		struct ipa_ioc_get_hdr sRetHeader;
+		IPAFilteringTable cFilterTable;
+		struct ipa_flt_rule_add sFilterRuleEntry;
+		uint32_t nRTTableHdl=0;
+		memset(&sRoutingTable, 0, sizeof(sRoutingTable));
+		memset(&sRetHeader, 0, sizeof(sRetHeader));
+		strlcpy(sRetHeader.name, "IEEE802_3", sizeof(sRetHeader.name));
+
+		LOG_MSG_STACK("Entering Function");
+		// Create Header:
+		// Allocate Memory, populate it, and add in to the Header Insertion.
+		struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+		pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+				sizeof(struct ipa_ioc_add_hdr)
+						+ 1 * sizeof(struct ipa_hdr_add));
+		if (!pHeaderDescriptor) {
+			LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+			bRetVal = false;
+			goto bail;
+		}
+		pHeaderDescriptor->commit = true;
+		pHeaderDescriptor->num_hdrs = 1;
+		strlcpy(pHeaderDescriptor->hdr[0].name, sRetHeader.name, sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+		memcpy(pHeaderDescriptor->hdr[0].hdr, m_aHeadertoAdd,
+				m_nHeadertoAddSize); //Header's Data
+    pHeaderDescriptor->hdr[0].hdr[12] = 0x00; //set length to zero, to confirm if ipa updates or not
+		pHeaderDescriptor->hdr[0].hdr_len = m_nHeadertoAddSize;
+		pHeaderDescriptor->hdr[0].hdr_hdl = -1; //Return Value
+		pHeaderDescriptor->hdr[0].is_partial = false;
+		pHeaderDescriptor->hdr[0].status = -1; // Return Parameter
+		strlcpy(sRetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sRetHeader.name));
+
+		if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+		{
+			LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+		if (!m_HeaderInsertion.GetHeaderHandle(&sRetHeader))
+		{
+			LOG_MSG_ERROR(" Failed");
+			bRetVal = false;
+			goto bail;
+		}
+		if (!CreateBypassRoutingTable(&m_Routing, m_eIP, bypass0, IPA_CLIENT_TEST3_CONS,
+				sRetHeader.hdl,&nRTTableHdl)) {
+			LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+		}
+		LOG_MSG_INFO("CreateBypassRoutingTable completed successfully");
+		sRoutingTable.ip = m_eIP;
+		strlcpy(sRoutingTable.name, bypass0, sizeof(sRoutingTable.name));
+		if (!m_Routing.GetRoutingTable(&sRoutingTable)) {
+			LOG_MSG_ERROR(
+					"m_routing.GetRoutingTable(&sRoutingTable=0x%p) Failed.", &sRoutingTable);
+			bRetVal = false;
+			goto bail;
+		}
+		// Creating Filtering Rules
+		cFilterTable.Init(m_eIP,IPA_CLIENT_TEST_PROD,false,1);
+		LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+		// Configuring Filtering Rule No.1
+		cFilterTable.GeneratePresetRule(0,sFilterRuleEntry);
+		sFilterRuleEntry.at_rear = true;
+		sFilterRuleEntry.flt_rule_hdl = -1; // return Value
+		sFilterRuleEntry.status = -1; // return value
+		sFilterRuleEntry.rule.action = IPA_PASS_TO_ROUTING;
+		sFilterRuleEntry.rule.rt_tbl_hdl = nRTTableHdl; //put here the handle corresponding to Routing Rule 1
+		if (
+				((uint8_t)-1 == cFilterTable.AddRuleToTable(sFilterRuleEntry)) ||
+				!m_Filtering.AddFilteringRule(cFilterTable.GetFilteringTable())
+				)
+		{
+			LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+			bRetVal = false;
+			goto bail;
+		} else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable.ReadRuleFromTable(0)->status);
+		}
+
+	bail:
+		Free(pHeaderDescriptor);
+		LOG_MSG_STACK(
+				"Leaving Function (Returning %s)", bRetVal?"True":"False");
+		return bRetVal;
+	} // AddRules()
+
+	virtual bool ModifyPackets() {
+		// This test doesn't modify the original IP Packet.
+		return true;
+	} // ModifyPacktes ()
+
+	virtual bool TestLogic() {
+		memset(m_aExpectedBuffer, 0, sizeof(m_aExpectedBuffer));
+		m_aExpectedBufSize = 0;
+
+		memcpy(m_aExpectedBuffer, m_aHeadertoAdd, m_nHeadertoAddSize);
+		memcpy(m_aExpectedBuffer+m_nHeadertoAddSize,m_aBuffer,m_uBufferSize);
+		m_aExpectedBufSize = m_nHeadertoAddSize + m_uBufferSize;
+		if (!SendReceiveAndCompare(&m_producer, m_aBuffer, m_uBufferSize,
+				&m_Consumer2, m_aExpectedBuffer, m_aExpectedBufSize)) {
+			LOG_MSG_ERROR("SendReceiveAndCompare failed.");
+			return false;
+		}
+		return true;
+	}
+private:
+	uint8_t m_aExpectedBuffer[BUFF_MAX_SIZE]; // Input file / IP packet
+	size_t m_aExpectedBufSize;
+	uint8_t m_aHeadertoAdd[MAX_HEADER_SIZE];
+	size_t m_nHeadertoAddSize;
+};
+
+//---------------------------------------------------------------------------/
+// Test003: Test Three Different Header Insertions                           /
+//---------------------------------------------------------------------------/
+class IPAHeaderInsertionTest003: public IPAHeaderInsertionTestFixture {
+public:
+	IPAHeaderInsertionTest003() :
+	m_aExpectedBufSize(BUFF_MAX_SIZE),
+	m_nHeadertoAddSize1(0),
+	m_nHeadertoAddSize2(0),
+	m_nHeadertoAddSize3(0)
+	{
+		m_name = "IPAHeaderInsertionTest003";
+		m_description =
+		"Header Insertion Test 003 - Test RmNet,IEEE802.3 and IEEE802.3 with const (1) addition to the length field\
+		1. Generate and commit two types of header Insertion RmNet and IEE802.3 \
+		2. Generate and commit three routing tables. \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+			Routing table 1 is used to add RmNet Header \
+			Routing table 2 is used to add IEEE802.3 Header (requires update of the Length field) \
+			Routing table 3 is used to add IEEE802.3 Header with additional const (1) to the length field \
+		3. Generate and commit Three filtering rules (MASK = 0xFF..FF). \
+			All DST_IP == 127.0.0.1 traffic goes to routing table 1 \
+			All DST_IP == 192.169.1.1 traffic goes to routing table 2 \
+			All DST_IP == 192.169.1.2 traffic goes to routing table 3";
+
+		Register(*this);
+		uint8_t aRMNetHeader[6] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
+		uint8_t aIEEE802_3Header1[22] = { 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+				0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0x00, 0x46, 0xAE, 0xAF, 0xB0,
+				0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6 };
+		uint8_t aIEEE802_3Header2[22] = { 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+				0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0x00, 0x47, 0xAE, 0xAF, 0xB0,
+				0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6 };
+		m_nHeadertoAddSize1 = sizeof(aRMNetHeader);
+		memcpy(m_aHeadertoAdd1, aRMNetHeader, m_nHeadertoAddSize1);
+		m_nHeadertoAddSize2 = sizeof(aIEEE802_3Header1);
+		memcpy(m_aHeadertoAdd2, aIEEE802_3Header1, m_nHeadertoAddSize2);
+		m_nHeadertoAddSize3 = sizeof(aIEEE802_3Header2);
+		memcpy(m_aHeadertoAdd3, aIEEE802_3Header2, m_nHeadertoAddSize3);
+	}
+
+	// Test Description:
+	// 1. Generate and commit single bypass routing table.
+	virtual bool AddRules() {
+		m_eIP = IPA_IP_v4;
+		const char aBypass1[20] = "Bypass1";
+		const char aBypass2[20] = "Bypass2";
+		const char aBypass3[20] = "Bypass3";
+		uint32_t nTableHdl01, nTableHdl02, nTableHdl03;
+		bool bRetVal = true;
+		IPAFilteringTable cFilterTable0;
+		struct ipa_flt_rule_add sFilterRuleEntry;
+		struct ipa_ioc_get_hdr sGetHeader1,sGetHeader2;
+
+		LOG_MSG_STACK("Entering Function");
+		memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+		memset(&sGetHeader1, 0, sizeof(sGetHeader1));
+		memset(&sGetHeader2, 0, sizeof(sGetHeader2));
+		// Create Header:
+		// Allocate Memory, populate it, and add in to the Header Insertion.
+		struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+		pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+				sizeof(struct ipa_ioc_add_hdr)
+						+ 2 * sizeof(struct ipa_hdr_add));
+		if (!pHeaderDescriptor) {
+			LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+			bRetVal = false;
+			goto bail;
+		}
+
+		pHeaderDescriptor->commit = true;
+		pHeaderDescriptor->num_hdrs = 2;
+		// Adding Header No1.
+		strlcpy(pHeaderDescriptor->hdr[0].name, "RMNet", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+		memcpy(pHeaderDescriptor->hdr[0].hdr, m_aHeadertoAdd1,
+				m_nHeadertoAddSize1); //Header's Data
+		pHeaderDescriptor->hdr[0].hdr_len    = m_nHeadertoAddSize1;
+		pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+		pHeaderDescriptor->hdr[0].is_partial = false;
+		pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+		// Adding Header No2.
+		strlcpy(pHeaderDescriptor->hdr[1].name, "IEEE_802_3", sizeof(pHeaderDescriptor->hdr[1].name)); // Header's Name
+		memcpy(pHeaderDescriptor->hdr[1].hdr, m_aHeadertoAdd2,
+				m_nHeadertoAddSize2); //Header's Data
+		pHeaderDescriptor->hdr[1].hdr_len    = m_nHeadertoAddSize2;
+		pHeaderDescriptor->hdr[1].hdr_hdl    = -1; //Return Value
+		pHeaderDescriptor->hdr[1].is_partial = false;
+		pHeaderDescriptor->hdr[1].status     = -1; // Return Parameter
+
+		strlcpy(sGetHeader1.name, pHeaderDescriptor->hdr[0].name, sizeof(sGetHeader1.name));
+		strlcpy(sGetHeader2.name, pHeaderDescriptor->hdr[1].name, sizeof(sGetHeader2.name));
+
+		if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+		{
+			LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+		if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader1))
+		{
+			LOG_MSG_ERROR(" Failed");
+			bRetVal = false;
+			goto bail;
+		}
+		LOG_MSG_DEBUG("Received Header1 Handle = 0x%x",sGetHeader1.hdl);
+		if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader2))
+		{
+			LOG_MSG_ERROR(" Failed");
+			bRetVal = false;
+			goto bail;
+		}
+		LOG_MSG_DEBUG("Received Header2 Handle = 0x%x",sGetHeader2.hdl);
+		if (!CreateBypassRoutingTable(&m_Routing, m_eIP, aBypass1, IPA_CLIENT_TEST2_CONS,
+				sGetHeader1.hdl,&nTableHdl01)) {
+			LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+		}
+		if (!CreateBypassRoutingTable(&m_Routing, m_eIP, aBypass2, IPA_CLIENT_TEST3_CONS,
+				sGetHeader2.hdl,&nTableHdl02)) {
+			LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+		}
+		if (!CreateBypassRoutingTable(&m_Routing, m_eIP, aBypass3, IPA_CLIENT_TEST4_CONS,
+				sGetHeader2.hdl,&nTableHdl03)) {
+			LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+		}
+		LOG_MSG_INFO("Creation of three bypass routing tables completed successfully TblHdl1=0x%x, TblHdl2=0x%x, TblHdl3=0x%x",
+				nTableHdl01,nTableHdl02,nTableHdl03);
+
+		// Creating Filtering Rules
+		cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST_PROD,false,3);
+		LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+		// Configuring Filtering Rule No.1
+		cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+		sFilterRuleEntry.at_rear = true;
+		sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+		sFilterRuleEntry.status = -1; // return value
+		sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+		sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl01; //put here the handle corresponding to Routing Rule 1
+		sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+		sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		if ((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry))
+		{
+			LOG_MSG_ERROR ("Adding Rule (0) to Filtering table Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+
+		// Configuring Filtering Rule No.2
+		sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+		sFilterRuleEntry.status = -1; // return Value
+		sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl02; //put here the handle corresponding to Routing Rule 2
+		sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0xC0A80101; // Filter DST_IP == 192.168.1.1.
+		if ((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry))
+		{
+			LOG_MSG_ERROR ("Adding Rule(1) to Filtering table Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+
+		// Configuring Filtering Rule No.3
+		sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+		sFilterRuleEntry.status = -1; // return value
+		sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl03; //put here the handle corresponding to Routing Rule 2
+		sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+		if ((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry))
+		{
+			LOG_MSG_ERROR ("Adding Rule(2) to Filtering table Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+
+		if (!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())) {
+			LOG_MSG_ERROR ("Failed to commit Filtering rules");
+			bRetVal = false;
+			goto bail;
+		}
+
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(1)->status);
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(2)->status);
+
+	bail:
+		Free(pHeaderDescriptor);
+		LOG_MSG_STACK(
+				"Leaving Function (Returning %s)", bRetVal?"True":"False");
+		return bRetVal;
+	} // AddRules()
+
+	virtual bool ModifyPackets() {
+		// This test doesn't modify the original IP Packet.
+		return true;
+	} // ModifyPacktes ()
+
+	virtual bool TestLogic() {
+		bool bRetVal = true;
+		m_aExpectedBufSize = 0;
+		uint32_t nIPv4DSTAddr;
+
+		LOG_MSG_STACK("Entering Function");
+
+		//Packet No. 1
+		memset(m_aExpectedBuffer, 0, sizeof(m_aExpectedBuffer));
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&m_aBuffer[IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,sizeof(nIPv4DSTAddr));
+		memcpy(m_aExpectedBuffer, m_aHeadertoAdd1, m_nHeadertoAddSize1);
+		memcpy(m_aExpectedBuffer+m_nHeadertoAddSize1,m_aBuffer,m_uBufferSize);
+		m_aExpectedBufSize = m_nHeadertoAddSize1 + m_uBufferSize;
+		if (!SendReceiveAndCompare(&m_producer, m_aBuffer, m_uBufferSize,
+				&m_Consumer1, m_aExpectedBuffer, m_aExpectedBufSize))
+		{
+			LOG_MSG_ERROR("SendReceiveAndCompare failed.");
+			bRetVal=false;
+		}
+
+		//Packet No. 2
+		memset(m_aExpectedBuffer, 0, sizeof(m_aExpectedBuffer));
+		nIPv4DSTAddr = ntohl(0xC0A80101);//192.168.1.1
+		memcpy (&m_aBuffer[IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,sizeof(nIPv4DSTAddr));
+		memcpy(m_aExpectedBuffer, m_aHeadertoAdd2, m_nHeadertoAddSize2);
+		memcpy(m_aExpectedBuffer+m_nHeadertoAddSize2,m_aBuffer,m_uBufferSize);
+		m_aExpectedBufSize = m_nHeadertoAddSize2 + m_uBufferSize;
+		if (!SendReceiveAndCompare(&m_producer, m_aBuffer, m_uBufferSize,
+				&m_Consumer2, m_aExpectedBuffer, m_aExpectedBufSize))
+		{
+			LOG_MSG_ERROR("SendReceiveAndCompare failed.");
+			bRetVal=false;
+		}
+
+		//Packet No. 3
+		nIPv4DSTAddr = ntohl(0xC0A80102);//192.168.1.2
+		memcpy (&m_aBuffer[IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,sizeof(nIPv4DSTAddr));
+		memcpy(m_aExpectedBuffer, m_aHeadertoAdd3, m_nHeadertoAddSize3);
+		memcpy(m_aExpectedBuffer+m_nHeadertoAddSize3,m_aBuffer,m_uBufferSize);
+		m_aExpectedBufSize = m_nHeadertoAddSize3 + m_uBufferSize;
+		if (!SendReceiveAndCompare(&m_producer, m_aBuffer, m_uBufferSize,
+				&m_Consumer3, m_aExpectedBuffer, m_aExpectedBufSize))
+		{
+			LOG_MSG_ERROR("SendReceiveAndCompare failed.");
+			bRetVal=false;
+		}
+
+		LOG_MSG_STACK("Leaving Function (Returning %s)",bRetVal?"True":"False");
+		return bRetVal;
+	}
+private:
+	uint8_t m_aExpectedBuffer[BUFF_MAX_SIZE]; // Input file / IP packet
+	size_t m_aExpectedBufSize;
+	uint8_t m_aHeadertoAdd1[MAX_HEADER_SIZE],m_aHeadertoAdd2[MAX_HEADER_SIZE],m_aHeadertoAdd3[MAX_HEADER_SIZE];
+	size_t m_nHeadertoAddSize1,m_nHeadertoAddSize2,m_nHeadertoAddSize3;
+};
+
+class IPAHeaderInsertionTest004: public IPAHeaderInsertionTestFixture {
+public:
+	IPAHeaderInsertionTest004() {
+		m_name = "IPAHeaderInsertionTest004";
+		m_description =
+		"Header Insertion Test 004 - Test header insertion with bad len values.";
+		Register(*this);
+		uint8_t aRMNetHeader[6] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
+		m_nHeadertoAddSize = sizeof(aRMNetHeader);
+		memcpy(m_aHeadertoAdd, aRMNetHeader, m_nHeadertoAddSize);
+	}
+
+	virtual bool AddRules() {
+		// Not adding any rules here.
+		return true;
+	} // AddRules()
+
+	virtual bool ModifyPackets() {
+		// This test doesn't modify the original IP Packet.
+		return true;
+	} // ModifyPacktes ()
+
+	bool AddSingleHeaderAndCheck(uint8_t len) {
+		m_eIP = IPA_IP_v4;
+		bool bRetVal = true;
+		struct ipa_ioc_get_hdr sRetHeader;
+		memset(&sRetHeader, 0, sizeof(sRetHeader));
+		strlcpy(sRetHeader.name, "Generic", sizeof(sRetHeader.name));
+
+		LOG_MSG_STACK("Entering Function");
+		// Create Header:
+		// Allocate Memory, populate it, and add in to the Header Insertion.
+		struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+		pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+				sizeof(struct ipa_ioc_add_hdr)
+						+ 1 * sizeof(struct ipa_hdr_add));
+		if (!pHeaderDescriptor) {
+			LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+			bRetVal = false;
+			goto bail;
+		}
+		pHeaderDescriptor->commit = true;
+		pHeaderDescriptor->num_hdrs = 1;
+		strlcpy(pHeaderDescriptor->hdr[0].name, sRetHeader.name, sizeof(pHeaderDescriptor->hdr[0].name));
+		memcpy(pHeaderDescriptor->hdr[0].hdr, m_aHeadertoAdd,
+				m_nHeadertoAddSize); //Header's Data
+		pHeaderDescriptor->hdr[0].hdr_len = len;
+		pHeaderDescriptor->hdr[0].hdr_hdl = -1; //Return Value
+		pHeaderDescriptor->hdr[0].is_partial = false;
+		pHeaderDescriptor->hdr[0].status = -1; // Return Parameter
+		strlcpy(sRetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sRetHeader.name));
+
+		if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+		{
+			LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+
+		if (!m_HeaderInsertion.GetHeaderHandle(&sRetHeader))
+		{
+			LOG_MSG_ERROR(" Failed");
+			bRetVal = false;
+			goto bail;
+		}
+
+	bail:
+		Free(pHeaderDescriptor);
+		LOG_MSG_STACK(
+				"Leaving Function (Returning %s)", bRetVal?"True":"False");
+		return bRetVal;
+	} // AddSingleHeaderAndCheck()
+
+	virtual bool TestLogic() {
+
+		// Try to add headers with invalid values.
+		// Valid values are between 1 to IPA_HDR_MAX_SIZE (64).
+		// We expect the below functions to fail.
+		if (AddSingleHeaderAndCheck(0)) {
+			LOG_MSG_ERROR("This is unexpected, this can't succeed");
+			return false;
+		}
+
+		if (AddSingleHeaderAndCheck(MAX_HEADER_SIZE + 1)) {
+			LOG_MSG_ERROR("This is unexpected, this can't succeed");
+			return false;
+		}
+
+		// Add one header which is OK
+		if (!AddSingleHeaderAndCheck(m_nHeadertoAddSize)) {
+			LOG_MSG_ERROR("This is unexpected, this can't succeed");
+			return false;
+		}
+		return true;
+	}
+
+private:
+	uint8_t m_aHeadertoAdd[MAX_HEADER_SIZE];
+	size_t m_nHeadertoAddSize;
+};
+
+class IPAHeaderInsertionTest005: public IPAHeaderInsertionTestFixture {
+public:
+	IPAHeaderInsertionTest005() {
+		m_name = "IPAHeaderInsertionTest005";
+		m_description =
+		"Header Insertion Test 005 - Test Multiple RMNet Header Insertion\
+		- Stress test - Generate and commit multiple header Insertion";
+		this->m_runInRegression = false;
+		Register(*this);
+		uint8_t aRMNetHeader[6] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
+		m_nHeadertoAddSize = sizeof(aRMNetHeader);
+		memcpy(m_aHeadertoAdd, aRMNetHeader, m_nHeadertoAddSize);
+	}
+
+	// Test Description:
+	// 1. Generate and commit single bypass routing table.
+	virtual bool AddRules() {
+		m_eIP = IPA_IP_v4;
+		bool bRetVal = true;
+		struct ipa_ioc_get_hdr sRetHeader;
+		char Name[] = "IEEE802_3\0";
+
+		memset(&sRetHeader, 0, sizeof(sRetHeader));
+		strlcpy (sRetHeader.name, Name, sizeof(sRetHeader.name));
+		LOG_MSG_STACK("Entering Function");
+		// Create Header:
+		// Allocate Memory, populate it, and add in to the Header Insertion.
+		struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+		pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+				sizeof(struct ipa_ioc_add_hdr)
+						+ 1 * sizeof(struct ipa_hdr_add));
+		if (!pHeaderDescriptor) {
+			LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+			bRetVal = false;
+			goto bail;
+		}
+		pHeaderDescriptor->commit = true;
+		pHeaderDescriptor->num_hdrs = 1;
+		strlcpy(pHeaderDescriptor->hdr[0].name, sRetHeader.name, sizeof(pHeaderDescriptor->hdr[0].name));
+		memcpy(pHeaderDescriptor->hdr[0].hdr, m_aHeadertoAdd,
+				m_nHeadertoAddSize); //Header's Data
+		pHeaderDescriptor->hdr[0].hdr_len = m_nHeadertoAddSize;
+		pHeaderDescriptor->hdr[0].hdr_hdl = -1; //Return Value
+		pHeaderDescriptor->hdr[0].is_partial = false;
+		pHeaderDescriptor->hdr[0].status = -1; // Return Parameter
+		strlcpy(sRetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sRetHeader.name));
+
+		// stress test to check if the target crashes, failure is expected before reaching 500
+		for (int i = 0; i < 500; i++) {
+			LOG_MSG_DEBUG("IPAHeaderInsertionTest005::AddRules iter=%d\n",i);
+			if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+			{
+				LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed on %d iteration.\n",i);
+				goto bail;
+			}
+		}
+
+	bail:
+		Free(pHeaderDescriptor);
+		LOG_MSG_STACK(
+				"Leaving Function (Returning %s)", bRetVal?"True":"False");
+		return bRetVal;
+	} // AddRules()
+
+	virtual bool ModifyPackets() {
+		// This test doesn't modify the original IP Packet.
+		return true;
+	} // ModifyPacktes ()
+
+	virtual bool TestLogic() {
+		return true;
+	}
+private:
+	uint8_t m_aHeadertoAdd[MAX_HEADER_SIZE];
+	size_t m_nHeadertoAddSize;
+};
+
+static IPAHeaderInsertionTest001 ipaHeaderInsertionTest001;
+static IPAHeaderInsertionTest002 ipaHeaderInsertionTest002;
+static IPAHeaderInsertionTest003 ipaHeaderInsertionTest003;
+static IPAHeaderInsertionTest004 ipaHeaderInsertionTest004;
+static IPAHeaderInsertionTest005 ipaHeaderInsertionTest005;
+

+ 618 - 0
kernel-tests/HeaderProcessingContextTestFixture.cpp

@@ -0,0 +1,618 @@
+/*
+ * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "HeaderProcessingContextTestFixture.h"
+#include "TestsUtils.h"
+
+const Byte IpaHdrProcCtxTestFixture::WLAN_ETH2_HDR[WLAN_ETH2_HDR_SIZE] =
+{
+	// WLAN hdr - 4 bytes
+	0xa1, 0xb2, 0xc3, 0xd4,
+
+	// ETH2 - 14 bytes
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00
+};
+
+const Byte IpaHdrProcCtxTestFixture::ETH2_HDR[ETH_HLEN] =
+{
+	// ETH2 - 14 bytes
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00
+};
+
+const Byte IpaHdrProcCtxTestFixture::ETH2_8021Q_HDR[ETH8021Q_HEADER_LEN] =
+{
+	// 802_1Q - 18 bytes
+	// src and dst MAC - 6 + 6 bytes
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+	// 802_1Q tag - VLAN ID 3
+	0x81, 0x00, 0x00, 0x03,
+	// ethertype
+	0x00, 0x00
+};
+
+const Byte IpaHdrProcCtxTestFixture::WLAN_802_3_HDR[WLAN_802_3_HDR_SIZE] =
+{
+	// WLAN hdr - 4 bytes
+	0x0a, 0x0b, 0x0c, 0x0d,
+
+	// 802_3 - 26 bytes
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00
+};
+
+IpaHdrProcCtxTestFixture::IpaHdrProcCtxTestFixture():
+	m_procCtxHandleId(PROC_CTX_HANDLE_ID_MAX),
+	m_pCurrentProducer(NULL),
+	m_pCurrentConsumer(NULL),
+	m_sendSize1 (m_BUFF_MAX_SIZE),
+	m_sendSize2 (m_BUFF_MAX_SIZE),
+	m_expectedBufferSize1(0),
+	m_IpaIPType(IPA_IP_v4)
+{
+	memset(m_headerHandles, 0, sizeof(m_headerHandles));
+	memset(m_procCtxHHandles, 0, sizeof(m_procCtxHHandles));
+	memset(m_sendBuffer1, 0, sizeof(m_sendBuffer1));
+	memset(m_sendBuffer2, 0, sizeof(m_sendBuffer2));
+	memset(m_expectedBuffer1, 0, sizeof(m_expectedBuffer1));
+	m_testSuiteName.push_back("HdrProcCtx");
+}
+
+bool IpaHdrProcCtxTestFixture::Setup()
+{
+	ConfigureScenario(PHASE_TWENTY_TEST_CONFIGURATION);
+
+	// init producers
+	m_rndisEth2Producer.Open(INTERFACE0_TO_IPA_DATA_PATH,
+		INTERFACE0_FROM_IPA_DATA_PATH);
+	m_wlanEth2producer.Open(INTERFACE4_TO_IPA_DATA_PATH,
+		INTERFACE4_FROM_IPA_DATA_PATH);
+	m_eth2Producer.Open(INTERFACE5_TO_IPA_DATA_PATH,
+		INTERFACE5_FROM_IPA_DATA_PATH);
+
+	// init consumers
+	m_defaultConsumer.Open(INTERFACE1_TO_IPA_DATA_PATH,
+		INTERFACE1_FROM_IPA_DATA_PATH);
+	m_rndisEth2Consumer.Open(INTERFACE2_TO_IPA_DATA_PATH,
+		INTERFACE2_FROM_IPA_DATA_PATH);
+
+	if (!m_headerInsertion.DeviceNodeIsOpened())
+	{
+		LOG_MSG_ERROR("HeaderInsertion block is not ready "
+			"for immediate commands!\n");
+		return false;
+	}
+
+	if (!m_routing.DeviceNodeIsOpened())
+	{
+		LOG_MSG_ERROR("Routing block is not ready "
+			"for immediate commands!\n");
+		return false;
+	}
+
+	if (!m_filtering.DeviceNodeIsOpened())
+	{
+		LOG_MSG_ERROR("Filtering block is not ready "
+			"for immediate commands!\n");
+		return false;
+	}
+
+	// resetting this component will reset
+	// both Routing and Filtering tables
+	m_headerInsertion.Reset();
+
+	return true;
+} // Setup()
+
+bool IpaHdrProcCtxTestFixture::Teardown()
+{
+	m_rndisEth2Producer.Close();
+	m_wlanEth2producer.Close();
+	m_eth2Producer.Close();
+	m_defaultConsumer.Close();
+	m_rndisEth2Consumer.Close();
+	return true;
+} // Teardown()
+
+void IpaHdrProcCtxTestFixture::AddAllHeaders()
+{
+	for (int i = 0; i < HEADER_HANDLE_ID_MAX; i++) {
+		AddHeader(static_cast<HeaderHandleId>(i));
+	}
+}
+
+// Insert a single header
+void IpaHdrProcCtxTestFixture::AddHeader(HeaderHandleId handleId)
+{
+	static const int NUM_OF_HEADERS = 1;
+	struct ipa_ioc_add_hdr *hdrTable = NULL;
+	struct ipa_hdr_add *hdr = NULL;
+
+	// init hdr table
+	hdrTable = (struct ipa_ioc_add_hdr *) calloc(1,
+		sizeof(struct ipa_ioc_add_hdr)
+		+ NUM_OF_HEADERS * sizeof(struct ipa_hdr_add));
+	if (!hdrTable)
+	{
+		LOG_MSG_ERROR(
+			"calloc failed to allocate pHeaderDescriptor");
+		return;
+	}
+	hdrTable->commit = true;
+	hdrTable->num_hdrs = NUM_OF_HEADERS;
+
+	// init the hdr common fields
+	hdr = &hdrTable->hdr[0];
+	hdr->hdr_hdl = -1; //Return Value
+	hdr->is_partial = false;
+	hdr->status = -1; // Return Parameter
+
+	// init hdr specific fields
+	switch (handleId)
+	{
+	case HEADER_HANDLE_ID_WLAN_ETH2:
+		memcpy(hdr->hdr, WLAN_ETH2_HDR, WLAN_ETH2_HDR_SIZE);
+		hdr->hdr_len = WLAN_ETH2_HDR_SIZE;
+
+		strlcpy(hdr->name, "WLAN_ETH2", sizeof(hdr->name));
+		hdr->type = IPA_HDR_L2_ETHERNET_II;
+		break;
+
+	case HEADER_HANDLE_ID_RNDIS_ETH2:
+		if (!RNDISAggregationHelper::LoadRNDISEth2IP4Header(
+			hdr->hdr,
+			IPA_HDR_MAX_SIZE,
+			0,
+			(size_t*)&hdr->hdr_len))
+			return;
+
+		strlcpy(hdr->name, "RNDIS_ETH2", sizeof(hdr->name));
+		hdr->type = IPA_HDR_L2_ETHERNET_II;
+		break;
+
+	case HEADER_HANDLE_ID_ETH2:
+		strlcpy(hdr->name, "ETH2", sizeof(hdr->name));
+		memcpy(hdr->hdr, ETH2_HDR, ETH_HLEN);
+		hdr->type = IPA_HDR_L2_ETHERNET_II;
+		hdr->hdr_len = ETH_HLEN;
+
+		break;
+
+	case HEADER_HANDLE_ID_WLAN_802_3:
+		strlcpy(hdr->name, "WLAN_802_3", sizeof(hdr->name));
+		memcpy(hdr->hdr, WLAN_802_3_HDR, WLAN_802_3_HDR_SIZE);
+		hdr->type = IPA_HDR_L2_802_3;
+		hdr->hdr_len = WLAN_802_3_HDR_SIZE;
+
+		LOG_MSG_DEBUG(
+			"HEADER_HANDLE_ID_WLAN_802_3 NOT supported for now");
+		return;
+
+		break;
+	case HEADER_HANDLE_ID_VLAN_802_1Q:
+		strlcpy(hdr->name, "VLAN_8021Q", sizeof(hdr->name));
+		memcpy(hdr->hdr, ETH2_8021Q_HDR, ETH8021Q_HEADER_LEN);
+		hdr->type = IPA_HDR_L2_802_1Q;
+		hdr->hdr_len = ETH8021Q_HEADER_LEN;
+		break;
+
+	default:
+		LOG_MSG_ERROR("header handleId not supported.");
+		return;
+	}
+
+	// commit header to HW
+	if (!m_headerInsertion.AddHeader(hdrTable))
+	{
+		LOG_MSG_ERROR("m_headerInsertion.AddHeader() failed.");
+		return;
+	}
+
+	// save header handle
+	m_headerHandles[handleId] = hdr->hdr_hdl;
+}
+
+void IpaHdrProcCtxTestFixture::AddAllProcCtx()
+{
+	for (int i = 0; i <PROC_CTX_HANDLE_ID_MAX; i++)
+	{
+		AddProcCtx(static_cast<ProcCtxHandleId>(i));
+	}
+}
+
+// Insert a single proc_ctx
+void IpaHdrProcCtxTestFixture::AddProcCtx(ProcCtxHandleId handleId)
+{
+	static const int NUM_OF_PROC_CTX = 1;
+	struct ipa_ioc_add_hdr_proc_ctx *procCtxTable = NULL;
+	struct ipa_hdr_proc_ctx_add *procCtx = NULL;
+
+	// init proc ctx table
+	procCtxTable = (struct ipa_ioc_add_hdr_proc_ctx *)calloc(1,
+		sizeof(struct ipa_ioc_add_hdr_proc_ctx)
+		+ NUM_OF_PROC_CTX *
+		sizeof(struct ipa_hdr_proc_ctx_add));
+	if (!procCtxTable)
+	{
+		LOG_MSG_ERROR("calloc failed to allocate procCtxTable");
+		return;
+	}
+
+	procCtxTable->commit = true;
+	procCtxTable->num_proc_ctxs = NUM_OF_PROC_CTX;
+
+	// init proc_ctx common fields
+	procCtx = &procCtxTable->proc_ctx[0];
+	procCtx->proc_ctx_hdl = -1; // return value
+	procCtx->status = -1; // Return parameter
+
+	// init proc_ctx specific fields
+	switch (handleId)
+	{
+	case PROC_CTX_HANDLE_ID_ETH2_2_WLAN_ETH2:
+		procCtx->type = IPA_HDR_PROC_ETHII_TO_ETHII;
+		procCtx->hdr_hdl =
+			m_headerHandles[HEADER_HANDLE_ID_WLAN_ETH2];
+		break;
+
+	case PROC_CTX_HANDLE_ID_ETH2_2_RNDIS_ETH2:
+		procCtx->type = IPA_HDR_PROC_ETHII_TO_ETHII;
+		procCtx->hdr_hdl =
+			m_headerHandles[HEADER_HANDLE_ID_RNDIS_ETH2];
+		break;
+
+	case PROC_CTX_HANDLE_ID_ETH2_ETH2_2_ETH2:
+		procCtx->type = IPA_HDR_PROC_ETHII_TO_ETHII;
+		procCtx->hdr_hdl =
+			m_headerHandles[HEADER_HANDLE_ID_ETH2];
+		break;
+
+	case PROC_CTX_HANDLE_ID_WLAN_ETH2_2_802_3:
+		procCtx->type = IPA_HDR_PROC_ETHII_TO_802_3;
+		procCtx->hdr_hdl =
+			m_headerHandles[HEADER_HANDLE_ID_WLAN_802_3];
+		break;
+
+	case PROC_CTX_HANDLE_ID_RNDIS_802_3_2_ETH2:
+		procCtx->type = IPA_HDR_PROC_802_3_TO_ETHII;
+		procCtx->hdr_hdl =
+			m_headerHandles[HEADER_HANDLE_ID_RNDIS_ETH2];
+		break;
+
+	case PROC_CTX_HANDLE_ID_WLAN_802_3_2_ETH2:
+		procCtx->type = IPA_HDR_PROC_802_3_TO_802_3;
+		procCtx->hdr_hdl =
+			m_headerHandles[HEADER_HANDLE_ID_WLAN_802_3];
+		break;
+	case PROC_CTX_HANDLE_ID_802_1Q_2_802_1Q:
+		procCtx->type = IPA_HDR_PROC_ETHII_TO_ETHII_EX;
+		procCtx->hdr_hdl =
+			m_headerHandles[HEADER_HANDLE_ID_VLAN_802_1Q];
+		procCtx->generic_params.input_ethhdr_negative_offset = 18;
+		procCtx->generic_params.output_ethhdr_negative_offset = 18;
+		break;
+	case PROC_CTX_HANDLE_ID_802_1Q_2_ETH2:
+		procCtx->type = IPA_HDR_PROC_ETHII_TO_ETHII_EX;
+		procCtx->hdr_hdl =
+			m_headerHandles[HEADER_HANDLE_ID_ETH2];
+		procCtx->generic_params.input_ethhdr_negative_offset = 18;
+		procCtx->generic_params.output_ethhdr_negative_offset = 14;
+		break;
+	case PROC_CTX_HANDLE_ID_ETH2_2_802_1Q:
+		procCtx->type = IPA_HDR_PROC_ETHII_TO_ETHII_EX;
+		procCtx->hdr_hdl =
+			m_headerHandles[HEADER_HANDLE_ID_VLAN_802_1Q];
+		procCtx->generic_params.input_ethhdr_negative_offset = 14;
+		procCtx->generic_params.output_ethhdr_negative_offset = 18;
+		break;
+	case PROC_CTX_HANDLE_ID_ETH2_ETH2_2_ETH2_EX:
+		procCtx->type = IPA_HDR_PROC_ETHII_TO_ETHII_EX;
+		procCtx->hdr_hdl =
+			m_headerHandles[HEADER_HANDLE_ID_ETH2];
+		procCtx->generic_params.input_ethhdr_negative_offset = 14;
+		procCtx->generic_params.output_ethhdr_negative_offset = 14;
+		break;
+
+	default:
+		LOG_MSG_ERROR("proc ctx handleId %d not supported.", handleId);
+		return;
+	}
+
+	if (!m_headerInsertion.AddProcCtx(procCtxTable))
+	{
+		LOG_MSG_ERROR("m_headerInsertion.AddProcCtx(procCtxTable) failed.");
+		return;
+	}
+
+	// save proc_ctx handle
+	m_procCtxHHandles[handleId] = procCtx->proc_ctx_hdl;
+}
+
+void IpaHdrProcCtxTestFixture::AddRtBypassRule(uint32_t hdrHdl, uint32_t procCtxHdl)
+{
+	static const char bypass0[] = "bypass0";
+	struct ipa_ioc_get_rt_tbl routing_table0;
+
+	if (!CreateIPv4BypassRoutingTable (
+		bypass0,
+		hdrHdl,
+		procCtxHdl))
+	{
+		LOG_MSG_ERROR("CreateIPv4BypassRoutingTable Failed\n");
+		return;
+	}
+
+	routing_table0.ip = IPA_IP_v4;
+	strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+	if (!m_routing.GetRoutingTable(&routing_table0))
+	{
+		LOG_MSG_ERROR("m_routing.GetRoutingTable() Failed.");
+		return;
+	}
+
+	m_routingTableHdl = routing_table0.hdl;
+}
+
+void IpaHdrProcCtxTestFixture::AddFltBypassRule()
+{
+	IPAFilteringTable FilterTable0;
+	struct ipa_flt_rule_add flt_rule_entry;
+
+	FilterTable0.Init(IPA_IP_v4,m_currProducerClient,false,1);
+	printf("FilterTable*.Init Completed Successfully..\n");
+
+	// Configuring Filtering Rule No.0
+	FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+	flt_rule_entry.at_rear = true;
+	flt_rule_entry.flt_rule_hdl=-1; // return Value
+	flt_rule_entry.status = -1; // return value
+	flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+	flt_rule_entry.rule.rt_tbl_hdl=m_routingTableHdl;
+	flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+	flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000; // Mask - Bypass rule
+	flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x12345678; // Filter is irrelevant.
+	if (((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+		!m_filtering.AddFilteringRule(
+		FilterTable0.GetFilteringTable()))
+	{
+		LOG_MSG_ERROR(
+			"%s::m_filtering.AddFilteringRule() failed",
+			__FUNCTION__);
+		return;
+	}
+	else
+	{
+		printf("flt rule hdl0=0x%x, status=0x%x\n",
+			FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,
+			FilterTable0.ReadRuleFromTable(0)->status);
+	}
+}
+
+bool IpaHdrProcCtxTestFixture::ReceivePacketsAndCompare()
+{
+	size_t receivedBufferSize1 = 0;
+	bool isSuccess = true;
+
+	// Receive results
+	Byte *receivedBuffer1 = new Byte[m_BUFF_MAX_SIZE];
+
+	if (NULL == receivedBuffer1)
+	{
+		printf("Memory allocation error.\n");
+		return false;
+	}
+
+	receivedBufferSize1 = m_pCurrentConsumer->ReceiveData(
+		receivedBuffer1,
+		m_BUFF_MAX_SIZE);
+	printf("Received %zu bytes on %s.\n",
+		receivedBufferSize1,
+		m_pCurrentConsumer->m_fromChannelName.c_str());
+
+	// Compare results
+	if (!CompareResultVsGolden(
+		m_expectedBuffer1,
+		m_expectedBufferSize1,
+		receivedBuffer1,
+		receivedBufferSize1))
+	{
+		printf("Comparison of Buffer Failed!\n");
+		isSuccess = false;
+	}
+
+	printf("Expected buffer 1 - %zu bytes\n", m_expectedBufferSize1);
+	print_buff(m_expectedBuffer1, m_expectedBufferSize1);
+
+	printf("Received buffer 1 - %zu bytes\n", receivedBufferSize1);
+	print_buff(receivedBuffer1, receivedBufferSize1);
+
+	delete[] receivedBuffer1;
+
+	return isSuccess;
+}
+
+// Create 1 IPv4 bypass routing entry and commits it
+bool IpaHdrProcCtxTestFixture::CreateIPv4BypassRoutingTable (
+	const char *name,
+	uint32_t hdrHdl,
+	uint32_t procCtxHdl)
+{
+	printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+	struct ipa_ioc_add_rt_rule *rt_table = 0;
+	struct ipa_rt_rule_add *rt_rule_entry = NULL;
+
+	// Verify that only one is nonzero
+	if ((hdrHdl == 0 && procCtxHdl == 0) ||
+		(hdrHdl != 0 && procCtxHdl != 0))
+	{
+		LOG_MSG_ERROR("Error: hdrHdl = %u, procCtxHdl = %u\n");
+		return false;
+	}
+
+	rt_table = (struct ipa_ioc_add_rt_rule *)
+		calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+		1*sizeof(struct ipa_rt_rule_add));
+	if(!rt_table) {
+		LOG_MSG_ERROR("calloc failed to allocate rt_table\n");
+		return false;
+	}
+
+	rt_table->num_rules = 1;
+	rt_table->ip = IPA_IP_v4;
+	rt_table->commit = true;
+	strlcpy(rt_table->rt_tbl_name, name, sizeof(rt_table->rt_tbl_name));
+
+	rt_rule_entry = &rt_table->rules[0];
+	rt_rule_entry->at_rear = 0;
+	rt_rule_entry->rule.dst = m_currConsumerPipeNum;
+	rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+	rt_rule_entry->rule.attrib.u.v4.dst_addr = 0xaabbccdd;
+
+	// All Packets will get a "Hit"
+	rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+	rt_rule_entry->rule.hdr_hdl = hdrHdl;
+	rt_rule_entry->rule.hdr_proc_ctx_hdl = procCtxHdl;
+	if (false == m_routing.AddRoutingRule(rt_table))
+	{
+		printf("Routing rule addition(rt_table) failed!\n");
+		Free (rt_table);
+		return false;
+	}
+
+	Free (rt_table);
+	printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+	return true;
+}
+
+bool IpaHdrProcCtxTestFixture::AddRules()
+{
+	printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+	if (m_procCtxHandleId == PROC_CTX_HANDLE_ID_MAX)
+	{
+		LOG_MSG_ERROR("Test developer didn't implement "
+			"AddRules() or didn't set m_procCtxHandleId");
+		return false;
+	}
+
+	AddAllHeaders();
+
+	AddAllProcCtx();
+
+	AddRtBypassRule(0, m_procCtxHHandles[m_procCtxHandleId]);
+
+	AddFltBypassRule();
+
+	printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+	return true;
+
+}// AddRules()
+
+bool IpaHdrProcCtxTestFixture::SendPackets()
+{
+
+	bool isSuccess = false;
+
+	// Send first packet
+	isSuccess = m_pCurrentProducer->SendData(
+		m_sendBuffer1,
+		m_sendSize1);
+	if (false == isSuccess)
+	{
+		LOG_MSG_ERROR("SendPackets Buffer1 failed on client %d\n", m_currProducerClient);
+		return false;
+	}
+
+	return true;
+}
+
+bool IpaHdrProcCtxTestFixture::Run()
+{
+	bool res = false;
+	bool isSuccess = false;
+
+	printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+	res = AddRules();
+	if (false == res) {
+		printf("Failed adding filtering rules.\n");
+		return false;
+	}
+
+	// Load input data - IP packets
+	res = LoadPackets(m_IpaIPType);
+	if (false == res) {
+		printf("Failed loading packets.\n");
+		return false;
+	}
+
+	res = GenerateExpectedPackets();
+	if (false == res) {
+		printf("GenerateExpectedPackets failed\n");
+		return false;
+	}
+
+	res = SendPackets();
+	if (false == res) {
+		printf("SendPackets failed\n");
+		return false;
+	}
+
+	// Receive packets from the channels and compare results
+	isSuccess = ReceivePacketsAndCompare();
+
+	printf("Leaving %s, %s(), Returning %d\n",
+		__FUNCTION__,
+		__FILE__,
+		isSuccess);
+
+	return isSuccess;
+} // Run()
+
+IpaHdrProcCtxTestFixture::~IpaHdrProcCtxTestFixture()
+{
+	m_sendSize1 = 0;
+}
+
+RoutingDriverWrapper IpaHdrProcCtxTestFixture::m_routing;
+Filtering IpaHdrProcCtxTestFixture::m_filtering;
+HeaderInsertion IpaHdrProcCtxTestFixture::m_headerInsertion;
+

+ 218 - 0
kernel-tests/HeaderProcessingContextTestFixture.h

@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <cstring> // for memcpy
+#include "hton.h" // for htonl
+#include "InterfaceAbstraction.h"
+#include "Constants.h"
+#include "Logger.h"
+#include "TestsUtils.h"
+#include "Filtering.h"
+#include "HeaderInsertion.h"
+#include "RoutingDriverWrapper.h"
+#include "IPAFilteringTable.h"
+
+/*
+Processing context test design:
+
+1.	1 Producer with RNDIS de-aggregation and ETH2 header removal.
+2.	1 Producer with WLAN and ETH2 header removal.
+3.	1 default consumer.
+4.	1 RNDIS aggregation consumer.
+5.	1 FLT rule – accept all - points to 1 RT rule.
+6.	1 RT rule – accept all - points to specific test relevant proc_ctx.
+7.	All tests add all proc_ctx  (for all tests).
+8.	Proc_ctx to be added: 1 for each test – 3 altogether.
+	Proc_ctx of test 01 and 03 are the same.
+9.	Each test will send 1 packet and check that the packet is good
+	except test 03.
+10.	Test 03  the same as Test 01  but will send multiple packets
+	and expect 1 (RNDIS aggregation test).
+
+List of tests:
+00.	Header insertion scenario of [RNDIS][ETH_II][IP] -> [WLAN][ETH_II][IP]
+01.	Header insertion scenario of [WLAN][ETH_II][IP] -> [RNDIS][ETH_II][IP]
+02.	Header insertion scenario of [WLAN][ETH_II][IP] -> [WLAN’][ETH_II][IP]
+03.	Header insertion of [WLAN][ETH_II][IP] -> [RNDIS][ETH_II][IP]
+	with RNDIS aggregation.
+04.	Header insertion scenario when adding total header sizes > 2048
+05.	Header insertion scenario of [ETH_II][IP] -> [WLAN][ETH_II][IP]
+06.	Header insertion scenario of [WLAN][ETH_II][IP] -> [ETH_II][IP
+07.	Header insertion scenario of [ETH_II][IP] -> [ETH_II][IP]
+08.	Header insertion scenario of [RNDIS][ETH_II][IP] -> [WLAN][802.3][IP]
+09.	Header insertion scenario of [WLAN][802.3][IP] -> [RNDIS][ETH_II][IP]
+10.	Header insertion scenario of [ETH_II][IP] -> [WLAN][802.3][IP]
+11.	Header insertion scenario of [WLAN][802.3][IP] -> [WLAN’][802.3][IP]
+*/
+class IpaHdrProcCtxTestFixture : public TestBase
+{
+public:
+	enum HeaderHandleId
+	{
+		HEADER_HANDLE_ID_WLAN_ETH2,
+		HEADER_HANDLE_ID_RNDIS_ETH2,
+		HEADER_HANDLE_ID_ETH2,
+		HEADER_HANDLE_ID_WLAN_802_3,
+		HEADER_HANDLE_ID_VLAN_802_1Q,
+		HEADER_HANDLE_ID_MAX
+	};
+
+	enum ProcCtxHandleId
+	{
+		PROC_CTX_HANDLE_ID_ETH2_2_WLAN_ETH2,
+		PROC_CTX_HANDLE_ID_ETH2_2_RNDIS_ETH2,
+		PROC_CTX_HANDLE_ID_ETH2_ETH2_2_ETH2,
+		PROC_CTX_HANDLE_ID_WLAN_ETH2_2_802_3,
+		PROC_CTX_HANDLE_ID_RNDIS_802_3_2_ETH2,
+		PROC_CTX_HANDLE_ID_WLAN_802_3_2_ETH2,
+		PROC_CTX_HANDLE_ID_802_1Q_2_802_1Q,
+		PROC_CTX_HANDLE_ID_ETH2_2_802_1Q,
+		PROC_CTX_HANDLE_ID_802_1Q_2_ETH2,
+		PROC_CTX_HANDLE_ID_ETH2_ETH2_2_ETH2_EX,
+		PROC_CTX_HANDLE_ID_MAX
+	};
+
+	// header table consist of 9 bits and 4B units -> 2048
+	static const int m_ALL_HEADER_SIZE_LIMIT = 2048;
+
+	static const size_t m_BUFF_MAX_SIZE =
+		2 * RNDISAggregationHelper::RNDIS_AGGREGATION_BYTE_LIMIT;
+
+	// [WLAN][ETH2] header
+	static const Byte WLAN_ETH2_HDR[WLAN_ETH2_HDR_SIZE];
+
+	// [ETH2] header
+	static const Byte ETH2_HDR[ETH_HLEN];
+
+	// [ETH2_802_1Q] vlan header
+	static const Byte ETH2_8021Q_HDR[ETH8021Q_HEADER_LEN];
+
+	// [WLAN][802.3] header
+	static const Byte WLAN_802_3_HDR[WLAN_802_3_HDR_SIZE];
+
+	static Filtering m_filtering;
+	static RoutingDriverWrapper m_routing;
+	static HeaderInsertion m_headerInsertion;
+
+	// For each header type the handle is saved
+	// to be used by the processing context
+	uint32_t m_headerHandles[HEADER_HANDLE_ID_MAX];
+
+	// For each prco_ctx type the handle is saved
+	// to be used by the routing rule
+	uint32_t m_procCtxHHandles[PROC_CTX_HANDLE_ID_MAX];
+
+	// proc_ctx handle ID
+	ProcCtxHandleId m_procCtxHandleId;
+
+	// routing table handle
+	uint32_t m_routingTableHdl;
+
+	// Pipe with RNDIS and ETH2 header removal
+	InterfaceAbstraction m_rndisEth2Producer;
+
+	// Pipe with WLAN and ETH2 header removal
+	InterfaceAbstraction m_wlanEth2producer;
+
+	// Pipe with ETH2 header removal
+	InterfaceAbstraction m_eth2Producer;
+
+	// TODO: Pipe with WLAN and 802.3 header removal
+	InterfaceAbstraction m_wlan802_3producer;
+
+	// Pointer to current producer pipe used in the test
+	InterfaceAbstraction *m_pCurrentProducer;
+	ipa_client_type m_currProducerClient;
+
+	// Pipe of the WLAN ETH2 consumer
+	InterfaceAbstraction m_defaultConsumer;
+
+	// Pipe of the RNDIS ETH2 consumer
+	InterfaceAbstraction m_rndisEth2Consumer;
+
+	// Pointer to current consumer pipe used in the test
+	InterfaceAbstraction *m_pCurrentConsumer;
+	ipa_client_type m_currConsumerPipeNum;
+
+	// First input packet
+	Byte m_sendBuffer1[m_BUFF_MAX_SIZE];
+	size_t m_sendSize1;
+
+	// Second input packet
+	Byte m_sendBuffer2[m_BUFF_MAX_SIZE];
+	size_t m_sendSize2;
+
+	// First expected packet
+	Byte m_expectedBuffer1[m_BUFF_MAX_SIZE];
+	size_t m_expectedBufferSize1;
+
+	enum ipa_ip_type m_IpaIPType;
+
+	IpaHdrProcCtxTestFixture();
+
+	virtual bool Setup();
+	virtual bool Teardown();
+	virtual void AddAllHeaders();
+
+	// Insert a single header
+	virtual void AddHeader(HeaderHandleId handleId);
+	virtual void AddAllProcCtx();
+
+	// Insert a single proc_ctx
+	virtual void AddProcCtx(ProcCtxHandleId handleId);
+	virtual void AddRtBypassRule(uint32_t hdrHdl, uint32_t procCtxHdl);
+	virtual void AddFltBypassRule();
+	virtual bool LoadPackets(enum ipa_ip_type ip) = 0;
+
+	virtual bool ReceivePacketsAndCompare();
+
+	// Create 1 IPv4 bypass routing entry and commits it
+	virtual bool CreateIPv4BypassRoutingTable (
+		const char *name,
+		uint32_t hdrHdl,
+		uint32_t procCtxHdl);
+
+	virtual bool GenerateExpectedPackets() = 0;
+
+	virtual bool AddRules();
+
+	virtual bool SendPackets();
+
+	virtual bool Run();
+
+	~IpaHdrProcCtxTestFixture();
+
+private:
+};
+

+ 780 - 0
kernel-tests/HeaderProcessingContextTests.cpp

@@ -0,0 +1,780 @@
+/*
+ * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "HeaderProcessingContextTestFixture.h"
+
+/*----------------------------------------------------------------------------*/
+/* Test00: Header insertion scenario of [RNDIS][ETH_II][IP] ->                */
+/* [WLAN][ETH_II][IP]                                                         */
+/*----------------------------------------------------------------------------*/
+class IpaHdrProcCtxTest00 : public IpaHdrProcCtxTestFixture
+{
+public:
+	IpaHdrProcCtxTest00()
+	{
+		m_name = "IpaHdrProcCtxTest00";
+		m_description =
+			"Processing Context test 00 - \
+			of [RNDIS][ETH_II][IP] -> [WLAN][ETH_II][IP] \
+			1. Generate and commit all headers for all tests. \
+			2. Generate and commit all processing context rules \
+			for all tests.\
+			3. Generate and commit routing table 0. \
+			The table contains 1 \"bypass\" rule. \
+			All data goes to output pipe TEST2. \
+			Routing rule will use processing context ETH2_2_WLAN_ETH2 \
+			4. Generate and commit 1 filtering rule. \
+			All traffic goes to routing table 0";
+		m_pCurrentProducer = &m_rndisEth2Producer;
+		m_currProducerClient = IPA_CLIENT_TEST_PROD;
+		m_pCurrentConsumer = &m_defaultConsumer;
+		m_currConsumerPipeNum = IPA_CLIENT_TEST2_CONS;
+		m_procCtxHandleId = PROC_CTX_HANDLE_ID_ETH2_2_WLAN_ETH2;
+		m_minIPAHwType = IPA_HW_v2_5;
+		m_maxIPAHwType = IPA_HW_MAX;
+		m_runInRegression = false;
+		Register(*this);
+	}
+
+	virtual bool LoadPackets(enum ipa_ip_type ip)
+	{
+		if (!RNDISAggregationHelper::LoadRNDISPacket(
+			ip,
+			m_sendBuffer1,
+			m_sendSize1))
+		{
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+		printf ("Loaded %zu Bytes to Packet 1\n",m_sendSize1);
+
+		add_buff(m_sendBuffer1+RNDIS_HDR_SIZE, ETH_HLEN, 2);
+		print_buff(m_sendBuffer1, m_sendSize1);
+
+		return true;
+	}
+
+	virtual bool GenerateExpectedPackets()
+	{
+		m_expectedBufferSize1 = WLAN_ETH2_HDR_SIZE +
+			IP4_PACKET_SIZE;
+
+		// copy WLAN header to the beginning of the buffer
+		memcpy(m_expectedBuffer1, WLAN_ETH2_HDR, WLAN_HDR_SIZE);
+
+		// copy ETH+IP packet right after WLAN header
+		memcpy(m_expectedBuffer1 + WLAN_HDR_SIZE,
+			m_sendBuffer1 + RNDIS_HDR_SIZE,
+			ETH_HLEN + IP4_PACKET_SIZE);
+
+		return true;
+	} // GenerateExpectedPackets()
+};
+
+/*----------------------------------------------------------------------------*/
+/* Test01: Header insertion scenario of [WLAN][ETH_II][IP] ->                 */
+/* [RNDIS][ETH_II][IP]                                                        */
+/*----------------------------------------------------------------------------*/
+class IpaHdrProcCtxTest01 : public IpaHdrProcCtxTestFixture
+{
+public:
+	IpaHdrProcCtxTest01()
+	{
+		m_name = "IpaHdrProcCtxTest01";
+		m_description =
+			"Processing context test 01 - \
+			of [WLAN][ETH_II][IP] -> [RNDIS][ETH_II][IP] \
+			1. Generate and commit all headers for all tests. \
+			2. Generate and commit all processing context rules \
+			for all tests.\
+			3. Generate and commit routing table 0. \
+			The table contains 1 \"bypass\" rule. \
+			All data goes to output pipe TEST3. \
+			Routing rule will use processing context ETH2_2_RNDIS_ETH2 \
+			4. Generate and commit 1 filtering rule. \
+			All traffic goes to routing table 0";
+		m_pCurrentProducer = &m_wlanEth2producer;
+		m_currProducerClient = IPA_CLIENT_TEST2_PROD;
+		m_pCurrentConsumer = &m_rndisEth2Consumer;
+		m_currConsumerPipeNum = IPA_CLIENT_TEST3_CONS;
+		m_procCtxHandleId = PROC_CTX_HANDLE_ID_ETH2_2_RNDIS_ETH2;
+		m_minIPAHwType = IPA_HW_v2_5;
+		m_maxIPAHwType = IPA_HW_MAX;
+		m_runInRegression = false;
+		Register(*this);
+	}
+
+	virtual bool LoadPackets(enum ipa_ip_type ip)
+	{
+		// load WLAN ETH2 IP4 packet of size 1kB + 1 byte
+		// This size will trigger RNDIS aggregation later
+		m_sendSize1 =
+			RNDISAggregationHelper::RNDIS_AGGREGATION_BYTE_LIMIT + 1;
+
+		if (!WlanHelper::LoadWlanEth2IP4PacketByLength(
+			m_sendBuffer1,
+			m_BUFF_MAX_SIZE,
+			m_sendSize1,
+			0x01))
+			return false;
+
+		printf ("Loaded %zu Bytes to Packet 1\n",m_sendSize1);
+
+		add_buff(m_sendBuffer1+WLAN_HDR_SIZE, ETH_HLEN, 3);
+
+		print_buff(m_sendBuffer1, m_sendSize1);
+
+		return true;
+	}
+
+	virtual bool GenerateExpectedPackets()
+	{
+		size_t len = 0;
+		size_t eth2PacketSize = m_sendSize1 - WLAN_HDR_SIZE;
+
+		m_expectedBufferSize1 =	eth2PacketSize + RNDIS_HDR_SIZE;
+
+		// copy RNDIS header
+		if (!RNDISAggregationHelper::LoadRNDISHeader(
+			m_expectedBuffer1,
+			m_BUFF_MAX_SIZE,
+			m_expectedBufferSize1,
+			&len))
+		{
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+
+		// copy ETH2 packet after RNDIS header
+		memcpy(m_expectedBuffer1 + len,
+			m_sendBuffer1 + WLAN_HDR_SIZE,
+			eth2PacketSize);
+
+		return true;
+	} // GenerateExpectedPackets()
+};
+
+/*----------------------------------------------------------------------------*/
+/* Test02: Header insertion scenario of [WLAN][ETH_II][IP] ->                 */
+/* [WLAN'][ETH_II][IP]                                                        */
+/*----------------------------------------------------------------------------*/
+class IpaHdrProcCtxTest02 : public IpaHdrProcCtxTestFixture
+{
+public:
+	IpaHdrProcCtxTest02()
+	{
+		m_name = "IpaHdrProcCtxTest02";
+		m_description =
+			"Processing context test 02 - \
+			of [WLAN][ETH_II][IP] -> [WLAN'][ETH_II][IP] \
+			1. Generate and commit all headers for all tests. \
+			2. Generate and commit all processing context rules \
+			for all tests.\
+			3. Generate and commit routing table 0. \
+			The table contains 1 \"bypass\" rule. \
+			All data goes to output pipe TEST2. \
+			Routing rule will use processing context ETH2_2_WLAN_ETH2 \
+			4. Generate and commit 1 filtering rule. \
+			All traffic goes to routing table 0";
+		m_pCurrentProducer = &m_wlanEth2producer;
+		m_currProducerClient = IPA_CLIENT_TEST2_PROD;
+		m_pCurrentConsumer = &m_defaultConsumer;
+		m_currConsumerPipeNum = IPA_CLIENT_TEST2_CONS;
+		m_procCtxHandleId = PROC_CTX_HANDLE_ID_ETH2_2_WLAN_ETH2;
+		m_minIPAHwType = IPA_HW_v2_5;
+		m_maxIPAHwType = IPA_HW_MAX;
+		m_runInRegression = false;
+		Register(*this);
+	}
+
+	virtual bool LoadPackets(enum ipa_ip_type ip)
+	{
+		// load WLAN ETH2 IP4 packet of size 1kB
+		// This size will trigger RNDIS aggregation later
+		if (!WlanHelper::LoadWlanEth2IP4Packet(
+			m_sendBuffer1,
+			m_BUFF_MAX_SIZE,
+			&m_sendSize1))
+			return false;
+
+		printf ("Loaded %zu Bytes to Packet 1\n",m_sendSize1);
+
+		add_buff(m_sendBuffer1+WLAN_HDR_SIZE, ETH_HLEN, 5);
+
+		return true;
+	}
+
+	virtual bool GenerateExpectedPackets()
+	{
+		m_expectedBufferSize1 = m_sendSize1;
+		memcpy(m_expectedBuffer1, m_sendBuffer1, m_expectedBufferSize1);
+		memcpy(m_expectedBuffer1, WLAN_ETH2_HDR, WLAN_HDR_SIZE);
+
+		return true;
+	} // GenerateExpectedPackets()
+};
+
+/*----------------------------------------------------------------------------*/
+/* Test03: Header insertion scenario of [WLAN][ETH_II][IP] ->                 */
+/* [RNDIS][ETH_II][IP] with RNDIS aggregation                                 */
+/*----------------------------------------------------------------------------*/
+class IpaHdrProcCtxTest03 : public IpaHdrProcCtxTestFixture
+{
+public:
+	IpaHdrProcCtxTest03()
+	{
+		m_name = "IpaHdrProcCtxTest03";
+		m_description =
+			"Processing Context test 03 - \
+			of [RNDIS][ETH_II][IP] -> [WLAN][ETH_II][IP] \
+			with RNDIS aggregation \
+			1. Generate and commit all headers for all tests. \
+			2. Generate and commit all processing context rules \
+			for all tests.\
+			3. Generate and commit routing table 0. \
+			The table contains 1 \"bypass\" rule. \
+			All data goes to output pipe TEST3. \
+			Routing rule will use processing context ETH2_2_RNDIS_ETH2 \
+			4. Generate and commit 1 filtering rule. \
+			All traffic goes to routing table 0";
+		m_pCurrentProducer = &m_wlanEth2producer;
+		m_currProducerClient = IPA_CLIENT_TEST2_PROD;
+		m_pCurrentConsumer = &m_rndisEth2Consumer;
+		m_currConsumerPipeNum = IPA_CLIENT_TEST3_CONS;
+		m_procCtxHandleId = PROC_CTX_HANDLE_ID_ETH2_2_RNDIS_ETH2;
+		m_minIPAHwType = IPA_HW_v2_5;
+		m_maxIPAHwType = IPA_HW_MAX;
+		m_runInRegression = false;
+		Register(*this);
+	}
+
+	virtual bool LoadPackets(enum ipa_ip_type ip)
+	{
+		// choose this size so that 2 such buffers would be aggregated
+		m_sendSize1 = RNDISAggregationHelper::
+			RNDIS_AGGREGATION_BYTE_LIMIT /	2 + 200;
+
+		if (!WlanHelper::LoadWlanEth2IP4PacketByLength(
+			m_sendBuffer1,
+			m_BUFF_MAX_SIZE,
+			m_sendSize1,
+			1))
+			return false;
+
+		printf ("Loaded %zu Bytes to Packet 1\n", m_sendSize1);
+
+		add_buff(m_sendBuffer1+WLAN_HDR_SIZE, ETH_HLEN, 7);
+
+		// choose this size so that 2 such buffers would be aggregated
+		m_sendSize2 = RNDISAggregationHelper::
+			RNDIS_AGGREGATION_BYTE_LIMIT /	2 + 200;
+
+		if (!WlanHelper::LoadWlanEth2IP4PacketByLength(
+			m_sendBuffer2,
+			m_BUFF_MAX_SIZE,
+			m_sendSize2,
+			2))
+			return false;
+
+		printf ("Loaded %zu Bytes to Packet 2\n", m_sendSize2);
+
+		add_buff(m_sendBuffer2+WLAN_HDR_SIZE, ETH_HLEN, 11);
+
+		return true;
+	}
+
+	virtual bool SendPackets()
+	{
+		bool isSuccess = false;
+
+		// Send packet 1
+		isSuccess = m_pCurrentProducer->SendData(
+			m_sendBuffer1,
+			m_sendSize1);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR(
+				"SendData Buffer 1 failed on producer %d\n", m_currProducerClient);
+			return false;
+		}
+
+		// Send packet 2
+		isSuccess = m_pCurrentProducer->SendData(
+			m_sendBuffer2,
+			m_sendSize2);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR(
+				"SendData Buffer 2 failed on producer %d\n", m_currProducerClient);
+			return false;
+		}
+
+		return true;
+	}
+
+	virtual bool GenerateExpectedPackets()
+	{
+		size_t len = 0;
+		size_t eth2PacketSize1 = m_sendSize1 - WLAN_HDR_SIZE;
+		size_t rndisPacketSize1 = eth2PacketSize1 + RNDIS_HDR_SIZE;
+		size_t eth2PacketSize2 = m_sendSize2 - WLAN_HDR_SIZE;
+		size_t rndisPacketSize2 = eth2PacketSize2 + RNDIS_HDR_SIZE;
+		Byte *currBuffLocation = NULL;
+
+		m_expectedBufferSize1 = rndisPacketSize1 + rndisPacketSize2;
+
+		currBuffLocation = m_expectedBuffer1;
+
+		// copy first RNDIS header
+		if (!RNDISAggregationHelper::LoadRNDISHeader(
+			currBuffLocation,
+			m_BUFF_MAX_SIZE,
+			rndisPacketSize1,
+			&len))
+			return false;
+
+		// copy ETH2 packet 1 after RNDIS header
+		currBuffLocation += len;
+		memcpy(currBuffLocation,
+			m_sendBuffer1 + WLAN_HDR_SIZE,
+			eth2PacketSize1);
+
+		// copy second RNDIS header
+		currBuffLocation += eth2PacketSize1;
+		if (!RNDISAggregationHelper::LoadRNDISHeader(
+			currBuffLocation,
+			m_BUFF_MAX_SIZE - rndisPacketSize1,
+			rndisPacketSize2,
+			&len))
+			return false;
+
+		// copy ETH2 packet 2 after RNDIS header
+		currBuffLocation += len;
+		memcpy(currBuffLocation,
+			m_sendBuffer2 + WLAN_HDR_SIZE,
+			eth2PacketSize2);
+
+		return true;
+	} // GenerateExpectedPackets()
+};
+
+
+/*----------------------------------------------------------------------------*/
+/* Test04: Header insertion scenario when adding total header sizes > 2048    */
+/*----------------------------------------------------------------------------*/
+class IpaHdrProcCtxTest04 : public IpaHdrProcCtxTestFixture
+{
+public:
+	IpaHdrProcCtxTest04()
+	{
+		m_name = "IpaHdrProcCtxTest04";
+		m_description =
+			"Processing context test 04 - \
+			Header insertion scenario when adding \
+			total header sizes > 2048 \
+			1. Generate and commit all headers for all tests. \
+			2. Generate and commit all processing context rules \
+			for all tests.\
+			3. Generate and commit routing table 0. \
+			The table contains 1 \"bypass\" rule. \
+			All data goes to output pipe TEST2. \
+			Routing rule will use header WLAN_ETH2 \
+			4. Generate and commit 1 filtering rule. \
+			All traffic goes to routing table 0";
+		m_pCurrentProducer = &m_wlanEth2producer;
+		m_currProducerClient = IPA_CLIENT_TEST2_PROD;
+		m_pCurrentConsumer = &m_defaultConsumer;
+		m_currConsumerPipeNum = IPA_CLIENT_TEST2_CONS;
+		m_minIPAHwType = IPA_HW_v2_5;
+		m_maxIPAHwType = IPA_HW_MAX;
+		m_runInRegression = false;
+		Register(*this);
+	}
+
+	virtual void AddAllHeaders()
+	{
+		int cnt = 0;
+		int allHeadersSize = 0;
+
+		while (allHeadersSize <= m_ALL_HEADER_SIZE_LIMIT)
+		{
+			AddHeader(HEADER_HANDLE_ID_ETH2);
+			/* header bins are power of 2 */
+			allHeadersSize += ETH_HLEN + 2;
+			cnt++;
+		}
+
+		AddHeader(HEADER_HANDLE_ID_WLAN_ETH2);
+	}
+
+	virtual bool AddRules()
+	{
+		printf("Entering %s, %s()\n",__FUNCTION__, __FILE__);
+
+		AddAllHeaders();
+
+		AddRtBypassRule(m_headerHandles[HEADER_HANDLE_ID_WLAN_ETH2], 0);
+
+		AddFltBypassRule();
+
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+
+	}// AddRules()
+
+	virtual bool LoadPackets(enum ipa_ip_type ip)
+	{
+		// load WLAN ETH2 IP4 packet of size 1kB
+		// This size will trigger RNDIS aggregation later
+		if (!WlanHelper::LoadWlanEth2IP4Packet(
+			m_sendBuffer1,
+			m_BUFF_MAX_SIZE,
+			&m_sendSize1))
+			return false;
+
+		printf ("Loaded %zu Bytes to Packet 1\n",m_sendSize1);
+
+		add_buff(m_sendBuffer1+WLAN_HDR_SIZE, ETH_HLEN, 13);
+
+		return true;
+	}
+
+	virtual bool GenerateExpectedPackets()
+	{
+		m_expectedBufferSize1 = m_sendSize1;
+		memcpy(m_expectedBuffer1, m_sendBuffer1, m_expectedBufferSize1);
+		memcpy(m_expectedBuffer1, WLAN_ETH2_HDR, WLAN_ETH2_HDR_SIZE);
+
+		return true;
+	} // GenerateExpectedPackets()
+};
+
+/*----------------------------------------------------------------------------*/
+/* Test05: Header insertion scenario of [ETH_II_802_1Q][IP] ->                */
+/* [ETH_II_802_1Q][IP]                                                        */
+/*----------------------------------------------------------------------------*/
+class IpaHdrProcCtxTest05 : public IpaHdrProcCtxTestFixture
+{
+public:
+	IpaHdrProcCtxTest05()
+	{
+		m_name = "IpaHdrProcCtxTest05";
+		m_description =
+			"Processing Context test 05 - \
+			of [ETH_II_802_1Q][IP] -> [ETH_II_802_1Q][IP] \
+			1. Generate and commit all headers for all tests. \
+			2. Generate and commit all processing context rules \
+			for all tests.\
+			3. Generate and commit routing table 0. \
+			The table contains 1 \"bypass\" rule. \
+			All data goes to output pipe TEST2. \
+			Routing rule will use processing context 802_1Q_2_802_1Q \
+			4. Generate and commit 1 filtering rule. \
+			All traffic goes to routing table 0";
+		/*
+		 * NOTE: we use the wlan + ETH header prod pipe since the header
+		 * length shall be equal to 8021Q ETH_II length
+		 */
+		m_pCurrentProducer = &m_wlanEth2producer;
+		m_currProducerClient = IPA_CLIENT_TEST2_PROD;
+		m_pCurrentConsumer = &m_defaultConsumer;
+		m_currConsumerPipeNum = IPA_CLIENT_TEST2_CONS;
+		m_procCtxHandleId = PROC_CTX_HANDLE_ID_802_1Q_2_802_1Q;
+		m_minIPAHwType = IPA_HW_v4_0;
+		m_maxIPAHwType = IPA_HW_MAX;
+		m_runInRegression = false;
+		Register(*this);
+	}
+
+	virtual bool LoadPackets(enum ipa_ip_type ip)
+	{
+		if (!LoadDefault802_1Q(ip,
+			m_sendBuffer1,
+			m_sendSize1)) {
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+		printf("Loaded %zu Bytes to Packet 1\n", m_sendSize1);
+
+		// modify the MAC addresses only
+		add_buff(m_sendBuffer1, 12, 14);
+
+		//change vlan ID to 9
+		m_sendBuffer1[15] = 0x9;
+
+		print_buff(m_sendBuffer1, m_sendSize1);
+
+		return true;
+	}
+
+	virtual bool GenerateExpectedPackets()
+	{
+		m_expectedBufferSize1 = m_sendSize1;
+
+		// we actually expect the same packet to come out (but after uCP)
+		memcpy(m_expectedBuffer1, m_sendBuffer1, m_expectedBufferSize1);
+
+		return true;
+	} // GenerateExpectedPackets()
+};
+
+/*----------------------------------------------------------------------------*/
+/* Test06: Header insertion scenario of [ETH_II][IP] ->                       */
+/* [ETH_II_802_1Q][IP]                                                        */
+/*----------------------------------------------------------------------------*/
+class IpaHdrProcCtxTest06 : public IpaHdrProcCtxTestFixture
+{
+public:
+	IpaHdrProcCtxTest06()
+	{
+		m_name = "IpaHdrProcCtxTest06";
+		m_description =
+			"Processing Context test 06 - \
+			of [ETH_II][IP] -> [ETH_II_802_1Q][IP] \
+			1. Generate and commit all headers for all tests. \
+			2. Generate and commit all processing context rules \
+			for all tests.\
+			3. Generate and commit routing table 0. \
+			The table contains 1 \"bypass\" rule. \
+			All data goes to output pipe TEST2. \
+			Routing rule will use processing context ETH2_2_802_1Q \
+			4. Generate and commit 1 filtering rule. \
+			All traffic goes to routing table 0";
+
+		m_pCurrentProducer = &m_eth2Producer;
+		m_currProducerClient = IPA_CLIENT_TEST3_PROD;
+		m_pCurrentConsumer = &m_defaultConsumer;
+		m_currConsumerPipeNum = IPA_CLIENT_TEST2_CONS;
+		m_procCtxHandleId = PROC_CTX_HANDLE_ID_ETH2_2_802_1Q;
+		m_minIPAHwType = IPA_HW_v4_0;
+		m_maxIPAHwType = IPA_HW_MAX;
+		m_runInRegression = false;
+		Register(*this);
+	}
+
+	virtual bool LoadPackets(enum ipa_ip_type ip)
+	{
+		if (!Eth2Helper::LoadEth2IP4Packet(
+			m_sendBuffer1,
+			m_BUFF_MAX_SIZE,
+			&m_sendSize1)) {
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+
+		printf("Loaded %zu Bytes to Packet 1\n", m_sendSize1);
+
+		// modify the MAC addresses only
+		add_buff(m_sendBuffer1, 12, 15);
+
+		print_buff(m_sendBuffer1, m_sendSize1);
+
+		return true;
+	}
+
+	virtual bool GenerateExpectedPackets()
+	{
+		size_t len;
+
+		m_expectedBufferSize1 = ETH8021Q_HEADER_LEN +
+			IP4_PACKET_SIZE;
+		// copy the VLAN header to expected buffer
+		memcpy(m_expectedBuffer1, ETH2_8021Q_HDR, ETH8021Q_HEADER_LEN);
+
+		// fill src and dst mac and ethertype
+		memcpy(m_expectedBuffer1, m_sendBuffer1, 2 * ETH_ALEN);
+		memcpy(m_expectedBuffer1 + ETH8021Q_ETH_TYPE_OFFSET,
+			m_sendBuffer1 + ETH2_ETH_TYPE_OFFSET, ETH2_ETH_TYPE_LEN);
+
+		len = m_BUFF_MAX_SIZE - ETH8021Q_HEADER_LEN;
+		if (!LoadDefaultPacket(IPA_IP_v4,
+			m_expectedBuffer1 + ETH8021Q_HEADER_LEN,
+			len)) {
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+
+		return true;
+	} // GenerateExpectedPackets()
+};
+
+/*----------------------------------------------------------------------------*/
+/* Test07: Header insertion scenario of [ETH_II_802_1Q][IP] ->                */
+/* [ETH_II][IP]                                                               */
+/*----------------------------------------------------------------------------*/
+class IpaHdrProcCtxTest07 : public IpaHdrProcCtxTestFixture
+{
+public:
+	IpaHdrProcCtxTest07()
+	{
+		m_name = "IpaHdrProcCtxTest07";
+		m_description =
+			"Processing Context test 07 - \
+			of [ETH_II_802_1Q][IP] -> [ETH_II][IP] \
+			1. Generate and commit all headers for all tests. \
+			2. Generate and commit all processing context rules \
+			for all tests.\
+			3. Generate and commit routing table 0. \
+			The table contains 1 \"bypass\" rule. \
+			All data goes to output pipe TEST2. \
+			Routing rule will use processing context 802_1Q_2_ETH2 \
+			4. Generate and commit 1 filtering rule. \
+			All traffic goes to routing table 0";
+
+		m_pCurrentProducer = &m_wlanEth2producer;
+		m_currProducerClient = IPA_CLIENT_TEST2_PROD;
+		m_pCurrentConsumer = &m_defaultConsumer;
+		m_currConsumerPipeNum = IPA_CLIENT_TEST2_CONS;
+		m_procCtxHandleId = PROC_CTX_HANDLE_ID_802_1Q_2_ETH2;
+		m_minIPAHwType = IPA_HW_v4_0;
+		m_maxIPAHwType = IPA_HW_MAX;
+		m_runInRegression = false;
+		Register(*this);
+	}
+
+	virtual bool LoadPackets(enum ipa_ip_type ip)
+	{
+		if (!LoadDefault802_1Q(ip,
+			m_sendBuffer1,
+			m_sendSize1)) {
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+
+		printf("Loaded %zu Bytes to Packet 1\n", m_sendSize1);
+
+		// modify the MAC addresses only
+		add_buff(m_sendBuffer1, ETH8021Q_METADATA_OFFSET, 16);
+
+		print_buff(m_sendBuffer1, m_sendSize1);
+
+		return true;
+	}
+
+	virtual bool GenerateExpectedPackets()
+	{
+		size_t len;
+
+		m_expectedBufferSize1 = m_sendSize1 - ETH8021Q_8021Q_TAG_LEN;
+
+		// copy the ETH2 header to expected buffer
+		memcpy(m_expectedBuffer1, ETH2_HDR, ETH_HLEN);
+
+		// fill src and dst mac and ethertype
+		memcpy(m_expectedBuffer1, m_sendBuffer1, 2 * ETH_ALEN);
+		memcpy(m_expectedBuffer1 + ETH2_ETH_TYPE_OFFSET,
+			m_sendBuffer1 + ETH8021Q_ETH_TYPE_OFFSET,
+			ETH2_ETH_TYPE_LEN);
+
+		len = m_BUFF_MAX_SIZE - ETH_HLEN;
+		if (!LoadDefaultPacket(IPA_IP_v4,
+			m_expectedBuffer1 + ETH_HLEN,
+			len)) {
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+
+		return true;
+	} // GenerateExpectedPackets()
+};
+
+/*----------------------------------------------------------------------------*/
+/* Test08: Header insertion scenario of [ETH_II][IP] ->                       */
+/* [ETH_II][IP] with generic ucp command                                      */
+/*----------------------------------------------------------------------------*/
+class IpaHdrProcCtxTest08 : public IpaHdrProcCtxTestFixture
+{
+public:
+	IpaHdrProcCtxTest08()
+	{
+		m_name = "IpaHdrProcCtxTest08";
+		m_description =
+			"Processing Context test 08 - \
+			of [ETH_II][IP] -> [ETH_II][IP] with generic ucp \
+			1. Generate and commit all headers for all tests. \
+			2. Generate and commit all processing context rules \
+			for all tests.\
+			3. Generate and commit routing table 0. \
+			The table contains 1 \"bypass\" rule. \
+			All data goes to output pipe TEST2. \
+			Routing rule will use processing context ETH2_2_ETH2_EX \
+			4. Generate and commit 1 filtering rule. \
+			All traffic goes to routing table 0";
+
+		m_pCurrentProducer = &m_eth2Producer;
+		m_currProducerClient = IPA_CLIENT_TEST3_PROD;
+		m_pCurrentConsumer = &m_defaultConsumer;
+		m_currConsumerPipeNum = IPA_CLIENT_TEST2_CONS;
+		m_procCtxHandleId = PROC_CTX_HANDLE_ID_ETH2_ETH2_2_ETH2_EX;
+		m_minIPAHwType = IPA_HW_v4_0;
+		m_maxIPAHwType = IPA_HW_MAX;
+		m_runInRegression = false;
+		Register(*this);
+	}
+
+	virtual bool LoadPackets(enum ipa_ip_type ip)
+	{
+		if (!Eth2Helper::LoadEth2IP4Packet(
+			m_sendBuffer1,
+			m_BUFF_MAX_SIZE,
+			&m_sendSize1)) {
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+
+		printf("Loaded %zu Bytes to Packet 1\n", m_sendSize1);
+
+		// modify the MAC addresses only
+		add_buff(m_sendBuffer1, 12, 17);
+
+		print_buff(m_sendBuffer1, m_sendSize1);
+
+		return true;
+	}
+
+	virtual bool GenerateExpectedPackets()
+	{
+		m_expectedBufferSize1 = m_sendSize1;
+
+		// we actually expect the same packet to come out (but after uCP)
+		memcpy(m_expectedBuffer1, m_sendBuffer1, m_expectedBufferSize1);
+
+		return true;
+	} // GenerateExpectedPackets()
+};
+
+static IpaHdrProcCtxTest00 ipaHdrProcCtxTest00;
+static IpaHdrProcCtxTest01 ipaHdrProcCtxTest01;
+static IpaHdrProcCtxTest02 ipaHdrProcCtxTest02;
+static IpaHdrProcCtxTest03 ipaHdrProcCtxTest03;
+static IpaHdrProcCtxTest04 ipaHdrProcCtxTest04;
+static IpaHdrProcCtxTest05 ipaHdrProcCtxTest05;
+static IpaHdrProcCtxTest06 ipaHdrProcCtxTest06;
+static IpaHdrProcCtxTest07 ipaHdrProcCtxTest07;
+static IpaHdrProcCtxTest08 ipaHdrProcCtxTest08;

+ 404 - 0
kernel-tests/HeaderRemovalTestFixture.cpp

@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "HeaderRemovalTestFixture.h"
+
+#include "Constants.h"
+#include "Logger.h"
+#include "IPAFilteringTable.h"
+
+#define IPA_TEST_DMUX_HEADER_LENGTH           8
+#define IPA_TEST_META_DATA_IS_VALID           1
+#define IPA_TEST_DMUX_HEADER_META_DATA_OFFSET 4
+
+extern Logger g_Logger;
+
+/////////////////////////////////////////////////////////////////////////////////
+
+//define the static Pipes which will be used by all derived tests.
+Pipe HeaderRemovalTestFixture::m_A2NDUNToIpaPipe(IPA_CLIENT_TEST2_PROD, IPA_TEST_CONFIFURATION_3);
+Pipe HeaderRemovalTestFixture::m_IpaToUsbPipe(IPA_CLIENT_TEST_CONS, IPA_TEST_CONFIFURATION_3);
+Pipe HeaderRemovalTestFixture::m_IpaToA2NDUNPipe(IPA_CLIENT_TEST2_CONS, IPA_TEST_CONFIFURATION_3);
+Pipe HeaderRemovalTestFixture::m_IpaToQ6LANPipe(IPA_CLIENT_TEST4_CONS, IPA_TEST_CONFIFURATION_3);
+RoutingDriverWrapper   HeaderRemovalTestFixture::m_routing;
+Filtering HeaderRemovalTestFixture::m_filtering;
+const char HeaderRemovalTestFixture_bypass0[20] = "Bypass0";
+const char HeaderRemovalTestFixture_bypassIPv60[20] = "BypassIPv60";
+
+/////////////////////////////////////////////////////////////////////////////////
+
+HeaderRemovalTestFixture::HeaderRemovalTestFixture()
+{
+	m_testSuiteName.push_back("Removal");
+	Register(*this);
+}
+
+static int SetupKernelModule(void)
+{
+	int retval;
+	struct ipa_channel_config from_ipa_channels[3];
+	struct test_ipa_ep_cfg from_ipa_cfg[3];
+	struct ipa_channel_config to_ipa_channels[1];
+	struct test_ipa_ep_cfg to_ipa_cfg[1];
+
+	struct ipa_test_config_header header = {0};
+	struct ipa_channel_config *to_ipa_array[1];
+	struct ipa_channel_config *from_ipa_array[3];
+
+	/* From ipa configurations - 3 pipes */
+	memset(&from_ipa_cfg[0], 0, sizeof(from_ipa_cfg[0]));
+	prepare_channel_struct(&from_ipa_channels[0],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST_CONS,
+			(void *)&from_ipa_cfg[0],
+			sizeof(from_ipa_cfg[0]));
+	from_ipa_array[0] = &from_ipa_channels[0];
+
+	memset(&from_ipa_cfg[1], 0, sizeof(from_ipa_cfg[1]));
+	prepare_channel_struct(&from_ipa_channels[1],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST2_CONS,
+			(void *)&from_ipa_cfg[1],
+			sizeof(from_ipa_cfg[1]));
+	from_ipa_array[1] = &from_ipa_channels[1];
+
+	memset(&from_ipa_cfg[2], 0, sizeof(from_ipa_cfg[2]));
+	prepare_channel_struct(&from_ipa_channels[2],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST4_CONS,
+			(void *)&from_ipa_cfg[2],
+			sizeof(from_ipa_cfg[2]));
+	from_ipa_array[2] = &from_ipa_channels[2];
+
+	/* To ipa configurations - 1 pipes */
+	memset(&to_ipa_cfg[0], 0, sizeof(to_ipa_cfg[0]));
+	to_ipa_cfg[0].hdr.hdr_len = IPA_TEST_DMUX_HEADER_LENGTH;
+	to_ipa_cfg[0].hdr.hdr_ofst_metadata_valid = IPA_TEST_META_DATA_IS_VALID;
+	to_ipa_cfg[0].hdr.hdr_ofst_metadata =
+		IPA_TEST_DMUX_HEADER_META_DATA_OFFSET;
+	prepare_channel_struct(&to_ipa_channels[0],
+			header.to_ipa_channels_num++,
+			IPA_CLIENT_TEST2_PROD,
+			(void *)&to_ipa_cfg[0],
+			sizeof(to_ipa_cfg[0]));
+	to_ipa_array[0] = &to_ipa_channels[0];
+
+	header.head_marker = IPA_TEST_CONFIG_MARKER;
+	header.tail_marker = IPA_TEST_CONFIG_MARKER;
+
+	prepare_header_struct(&header, from_ipa_array, to_ipa_array);
+
+	retval = GenericConfigureScenario(&header);
+
+	return retval;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool HeaderRemovalTestFixture::Setup()
+{
+	bool bRetVal = true;
+
+	//Set the configuration to support USB->IPA and IPA->USB pipes.
+	//ConfigureScenario(PHASE_THREE_TEST_CONFIGURATION);
+
+	bRetVal = SetupKernelModule();
+	if (bRetVal != true) {
+		return bRetVal;
+	}
+
+	//Initialize the pipe for all the tests - this will open the inode which represents the pipe.
+	bRetVal &= m_A2NDUNToIpaPipe.Init();
+	bRetVal &= m_IpaToUsbPipe.Init();
+	bRetVal &= m_IpaToA2NDUNPipe.Init();
+	bRetVal &= m_IpaToQ6LANPipe.Init();
+
+	// remove default "LAN" routing table (as we want to pass to USB pipe)
+	m_routing.Reset(IPA_IP_v4);
+	m_routing.Reset(IPA_IP_v6);
+
+	return bRetVal;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool HeaderRemovalTestFixture::Teardown()
+{
+	//The Destroy method will close the inode.
+	m_A2NDUNToIpaPipe.Destroy();
+	m_IpaToUsbPipe.Destroy();
+	m_IpaToA2NDUNPipe.Destroy();
+	m_IpaToQ6LANPipe.Destroy();
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+Byte* HeaderRemovalTestFixture::CreateA2NDUNPacket(
+		unsigned int magicNumber,
+		unsigned int nID,
+		string sPayloadFileName,
+		unsigned int *nTotalLength)
+{
+	size_t nIpv4ByteSize = 1024;
+	bool bRetVal = false;
+	Byte *pA2NDUNPacket = 0;
+	unsigned int nA2NDUNPacketByteSize = 0;
+	Byte *pIpv4Packet = (Byte*) malloc(1024);
+
+	if(0 == pIpv4Packet)
+	{
+		LOG_MSG_ERROR("Cannot allocate the memory for IPv4 packet");
+		return 0;
+	}
+
+	bRetVal = LoadDefaultPacket(IPA_IP_v4, pIpv4Packet, nIpv4ByteSize);
+	if(false == bRetVal)
+	{
+		LOG_MSG_ERROR("Cannot load the packet");
+		pA2NDUNPacket = 0;
+		goto bail;
+	}
+	//Magic Number(4 Bytes) Logical Channel ID(2 Bytes)  Length(2 Bytes)
+	nA2NDUNPacketByteSize = m_A2NDUNToIpaPipe.GetHeaderLengthAdd() +  nIpv4ByteSize;
+
+	pA2NDUNPacket = new Byte[ nA2NDUNPacketByteSize ];
+
+	//htobe32 for the magic number:
+	pA2NDUNPacket[0] = (magicNumber & 0xFF000000) >> 24;//MSB
+	pA2NDUNPacket[1] = (magicNumber & 0x00FF0000) >> 16;
+	pA2NDUNPacket[2] = (magicNumber & 0x0000FF00) >>  8;
+	pA2NDUNPacket[3] = (magicNumber & 0x000000FF) >>  0;//LSB
+
+	//htobe16 for the Logical Channel ID:
+	pA2NDUNPacket[4] = (nID & 0xFF00) >>  8;//MSB
+	pA2NDUNPacket[5] = (nID & 0x00FF) >>  0;//LSB
+
+	//htobe16 for the Length of the packet:
+	pA2NDUNPacket[6] = (nA2NDUNPacketByteSize & 0xFF00) >> 8;//MSB
+	pA2NDUNPacket[7] = (nA2NDUNPacketByteSize & 0x00FF) >> 0;//LSB
+
+	//add the payload to the A2NDUN packet
+	memcpy(&pA2NDUNPacket[8], pIpv4Packet, nIpv4ByteSize);
+
+	*nTotalLength = nA2NDUNPacketByteSize;
+
+/* fall through */
+
+bail:
+
+	Free(pIpv4Packet);
+
+	return pA2NDUNPacket;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool HeaderRemovalTestFixture::SetIPATablesToPassAllToSpecificClient(
+		enum ipa_client_type  nClientTypeSrc,
+		enum ipa_client_type nClientTypeDst)
+{
+	bool bRetVal = true;
+
+	bRetVal = SetRoutingTableToPassAllToSpecificClient(nClientTypeDst);
+	if(false == bRetVal)
+		goto bail;
+	bRetVal = SetFilterTableToPassAllToSpecificClient(nClientTypeSrc);
+	if(false == bRetVal)
+		goto bail;
+	bRetVal = SetHeaderInsertionTableAddEmptyHeaderForTheClient(nClientTypeSrc);
+	if(false == bRetVal)
+		goto bail;
+/* fall through */
+
+bail:
+	return bRetVal;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool  HeaderRemovalTestFixture::SetFilterTableToPassAllToSpecificClient(
+		enum ipa_client_type  nClientType)
+{
+	IPAFilteringTable         FilterTable;
+	struct ipa_flt_rule_add   flt_rule_entry;
+	struct ipa_ioc_get_rt_tbl sRoutingTable;
+
+	sRoutingTable.ip = IPA_IP_v4;
+	strlcpy(sRoutingTable.name, "Bypass0", sizeof(sRoutingTable.name));
+
+	if (false == m_routing.GetRoutingTable(&sRoutingTable)) {
+	  LOG_MSG_ERROR("Configure the routing block first");
+	  return false;
+	}
+
+	FilterTable.Init(IPA_IP_v4, nClientType, false, 1);
+	FilterTable.GeneratePresetRule(0, flt_rule_entry);
+	flt_rule_entry.at_rear                        = true;
+	flt_rule_entry.flt_rule_hdl                   = -1;
+	flt_rule_entry.status                         = -1;
+	flt_rule_entry.rule.action                    = IPA_PASS_TO_ROUTING;
+	flt_rule_entry.rule.rt_tbl_hdl                = sRoutingTable.hdl;
+	flt_rule_entry.rule.attrib.attrib_mask        = IPA_FLT_DST_ADDR;
+	flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+	flt_rule_entry.rule.attrib.u.v4.dst_addr      = 0x00000000;
+	if ((-1 == FilterTable.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable.GetFilteringTable())) {
+		LOG_MSG_INFO ("%s::Error Adding RuleTable(0) to Filtering, aborting...");
+		return false;
+	} else {
+		LOG_MSG_INFO( "flt rule hdl0=0x%x, status=0x%x",
+				FilterTable.ReadRuleFromTable(0)->flt_rule_hdl,
+					FilterTable.ReadRuleFromTable(0)->status);
+	}
+	LOG_MSG_INFO("Leaving ");
+
+	return true;
+}
+/////////////////////////////////////////////////////////////////////////////////
+
+bool  HeaderRemovalTestFixture::SetRoutingTableToPassAllToSpecificClient(
+		enum ipa_client_type  nClientType)
+{
+	if (!CreateBypassRoutingTablesIPv4(
+			HeaderRemovalTestFixture_bypass0,
+			nClientType)) {
+		LOG_MSG_INFO("CreateThreeBypassRoutingTables Failed");
+		return false;
+	}
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool  HeaderRemovalTestFixture::SetHeaderInsertionTableAddEmptyHeaderForTheClient(
+		enum ipa_client_type  nClientType)
+{
+	//TODO Header Removal: add header insertion data
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+// This function creates IPv4 bypass routing entry and commits it.
+bool HeaderRemovalTestFixture::CreateBypassRoutingTablesIPv4(
+		const char * bypass0,
+		enum ipa_client_type  nClientType)
+{
+	struct ipa_ioc_add_rt_rule *rt_rule0 = 0;
+	struct ipa_rt_rule_add *rt_rule_entry;
+
+	LOG_MSG_INFO("Entering");
+
+	rt_rule0 = (struct ipa_ioc_add_rt_rule *)
+		calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+				1*sizeof(struct ipa_rt_rule_add));
+	if (!rt_rule0) {
+		LOG_MSG_INFO("calloc failed to allocate rt_rule0");
+		return false;
+	}
+
+	rt_rule0->num_rules = 1;
+	rt_rule0->ip = IPA_IP_v4;
+	rt_rule0->commit = true;
+	strlcpy(rt_rule0->rt_tbl_name, bypass0, sizeof(rt_rule0->rt_tbl_name));
+
+	rt_rule_entry = &rt_rule0->rules[0];
+	rt_rule_entry->at_rear = 0;
+	rt_rule_entry->rule.dst = nClientType;
+//    rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // gidons, there is no support for header insertion / removal yet.
+	rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+	rt_rule_entry->rule.attrib.u.v4.dst_addr = 0xaabbccdd;
+	rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0x00000000;// All Packets will get a "Hit"
+	if (false == m_routing.AddRoutingRule(rt_rule0)) {
+		LOG_MSG_INFO("Routing rule addition(rt_rule0) failed!");
+		Free (rt_rule0);
+		return false;
+	}
+
+	Free (rt_rule0);
+	LOG_MSG_INFO("Leaving ");
+	return true;
+}
+
+bool HeaderRemovalTestFixture::ConfigureFilteringBlockWithMetaDataEq(
+		enum ipa_client_type  nClientType,
+		unsigned int nMetaData,
+		unsigned int nMetaDataMask)
+{
+	const char bypass0[20] = "Bypass0";
+	struct ipa_ioc_get_rt_tbl routing_table0;
+	IPAFilteringTable FilterTable0;
+	struct ipa_flt_rule_add flt_rule_entry;
+
+	LOG_MSG_INFO("Entering ");
+
+	if (!CreateBypassRoutingTablesIPv4(
+			HeaderRemovalTestFixture_bypass0,
+				nClientType)) {
+		LOG_MSG_INFO("CreateBypassRoutingTablesIPv4 Failed");
+		return false;
+	}
+
+	LOG_MSG_INFO("CreateBypassRoutingTablesIPv4 completed successfully");
+	routing_table0.ip = IPA_IP_v4;
+	strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+	if (!m_routing.GetRoutingTable(&routing_table0)) {
+		LOG_MSG_INFO(
+				"m_routing.GetRoutingTable(&routing_table0=0x%p) Failed."
+					,&routing_table0);
+		return false;
+	}
+
+	FilterTable0.Init(IPA_IP_v4, IPA_CLIENT_TEST2_PROD, false, 1);
+
+	LOG_MSG_INFO("FilterTable*.Init Completed Successfully..");
+
+	// Configuring Filtering Rule No.0
+	FilterTable0.GeneratePresetRule(1,flt_rule_entry);
+	flt_rule_entry.at_rear                        = true;
+	flt_rule_entry.flt_rule_hdl                   = -1; // return Value
+	flt_rule_entry.status                         = -1; // return value
+	flt_rule_entry.rule.action                    = IPA_PASS_TO_ROUTING;
+	flt_rule_entry.rule.rt_tbl_hdl                = routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+	flt_rule_entry.rule.attrib.attrib_mask        = IPA_FLT_META_DATA;
+	flt_rule_entry.rule.attrib.meta_data          = nMetaData;
+	flt_rule_entry.rule.attrib.meta_data_mask     = nMetaDataMask;
+	if ( (-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable()))
+	{
+		LOG_MSG_INFO ("%s::Error Adding RuleTable(0) to Filtering, aborting...");
+		return false;
+	} else {
+		LOG_MSG_INFO("flt rule hdl0=0x%x, status=0x%x", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,FilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+	LOG_MSG_INFO("Leaving ");
+
+	return true;
+}

+ 111 - 0
kernel-tests/HeaderRemovalTestFixture.h

@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _IPA_LINUX_TESTS_HR_TEST_FIXTURE_H_
+#define _IPA_LINUX_TESTS_HR_TEST_FIXTURE_H_
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "Constants.h"
+#include "Logger.h"
+#include "linux/msm_ipa.h"
+#include "TestsUtils.h"
+#include "TestBase.h"
+#include "Pipe.h"
+#include "RoutingDriverWrapper.h"
+#include "Filtering.h"
+
+/*This class will be the base class of all HeaderRemoval tests.
+ *Any method other than the test case itself can
+ *be declared in this Fixture thus allowing the derived classes to
+ *implement only the test case.
+ *All the test of the HeaderRemovalTestFixture
+ *uses one input and two output.
+ */
+class HeaderRemovalTestFixture:public TestBase
+{
+public:
+	/*This Constructor will register each instance
+	 * that it creates.*/
+	HeaderRemovalTestFixture();
+
+	/*This method will create and initialize two Pipe object for the USB
+	 *(Ethernet) Pipes, one as input and the other as output.
+	 */
+	virtual bool Setup();
+
+	/*This method will destroy the pipes.*/
+	virtual bool Teardown();
+
+	/*The client type are set from the peripheral perspective
+	 *(TODO Pipe:in case the Driver will change its perspective
+	 *of ipa_connect this should be changed).
+	 */
+	static Pipe m_A2NDUNToIpaPipe;
+	/*from the test application into the IPA(DMUX header)*/
+	static Pipe m_IpaToUsbPipe;
+	/*from the IPA back to the test application(Ethernet header)*/
+	static Pipe m_IpaToA2NDUNPipe;
+	/*from the IPA back to the test application(DMUX header)*/
+	static Pipe m_IpaToQ6LANPipe;
+
+	static RoutingDriverWrapper   m_routing;
+	static Filtering m_filtering;
+
+protected:
+	unsigned char *CreateA2NDUNPacket(unsigned int magicNumber,
+			unsigned int ID,
+			string sPayloadFileName,
+			unsigned int *nTotalLength);
+	bool  SetIPATablesToPassAllToSpecificClient(
+			enum ipa_client_type nClientTypeSrc,
+			enum ipa_client_type nClientTypeDst);
+	bool  SetFilterTableToPassAllToSpecificClient(
+			enum ipa_client_type nClientType);
+	bool  SetRoutingTableToPassAllToSpecificClient(
+			enum ipa_client_type nClientType);
+	bool  SetHeaderInsertionTableAddEmptyHeaderForTheClient(
+			enum ipa_client_type nClientType);
+	bool  CreateBypassRoutingTablesIPv4(
+			const char *bypass0,
+			enum ipa_client_type nClientType
+			);
+	bool ConfigureFilteringBlockWithMetaDataEq(
+			enum ipa_client_type nClientType,
+			unsigned int nMetaData,
+			unsigned int nMetaDataMask);
+};
+
+#endif
+

+ 218 - 0
kernel-tests/HeaderRemovalTests.cpp

@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "HeaderRemovalTests.h"
+#include "TestsUtils.h"
+#include <stdio.h>
+
+/////////////////////////////////////////////////////////////////////////////////
+
+static const unsigned int HEADER_REMOVAL_TEST_MAX_PACKET_BYTE_SIZE = 1024;
+
+/////////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+
+HeaderRemovalTOSCheck::HeaderRemovalTOSCheck()
+{
+	m_name = "HeaderRemovalTOSCheck";
+	m_description = "HeaderRemovalTOSCheck: Remove the header from the A2NDUN pipe and check the TOS field of the IP packet";
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool HeaderRemovalTOSCheck::Run()
+{
+	bool bTestResult = true;
+	Byte pPacketReceiveBuffer[HEADER_REMOVAL_TEST_MAX_PACKET_BYTE_SIZE] = {0};//This buffer will be used in order to store the received packet.
+
+	unsigned int nMagicNumber = 0x12345678; //arbitrary number
+	unsigned int nChannelID = 0xABCD;//arbitrary number
+	unsigned int nA2NDUNPacketByteSize = 0;
+	unsigned int nBytesSent = 0;
+	int          nBytesReceived = 0;
+	Byte *pA2NDUNPacket = CreateA2NDUNPacket(nMagicNumber, nChannelID, IPV4_FILE_PATH, &nA2NDUNPacketByteSize);
+	if(0 == pA2NDUNPacket) {
+	  LOG_MSG_ERROR("Cannot load file to memory, exiting");
+	  return false;
+	}
+	LOG_MSG_INFO("A2 Packet was  successfully created (%d bytes)", nA2NDUNPacketByteSize);
+
+	if ( false == SetIPATablesToPassAllToSpecificClient(IPA_CLIENT_TEST2_PROD, IPA_CLIENT_TEST_CONS)) {
+		LOG_MSG_ERROR("SetIPATablesToPassAllToSpecificClient failed, exiting test case");
+		bTestResult = false;
+		goto bail;
+	}
+
+	LOG_MSG_INFO("All tables were configured in order to output the packet to the correct pipe");
+
+	LOG_MSG_INFO("Sending packet into the A2NDUN pipe(%d bytes) and the Pipe will add an header",
+	             nA2NDUNPacketByteSize);
+
+	nBytesSent = m_A2NDUNToIpaPipe.Send(pA2NDUNPacket, nA2NDUNPacketByteSize);
+	if (nA2NDUNPacketByteSize != nBytesSent)
+	{
+		bTestResult = false;
+		goto bail;
+	}
+	//Receive the raw IP packet(which is a 4 arbitrary bytes) without header removal by the Pipe
+	LOG_MSG_INFO("Reading packet from the USB pipe");
+
+	nBytesReceived = m_IpaToUsbPipe.Receive(pPacketReceiveBuffer, HEADER_REMOVAL_TEST_MAX_PACKET_BYTE_SIZE);
+	//TODO Header Removal: at this point the success scenario is that data came to the correct pipe - change this to
+	//packet memory compare after header insertion is enabled.
+	if (0 == nBytesReceived)
+	{
+		bTestResult = false;
+		goto bail;
+	}
+
+	LOG_MSG_INFO("Read buffer : ");
+	//Print the output
+	for (int i = 0 ; i < nBytesReceived ; i++)
+	{
+	  printf("0x%02x", pPacketReceiveBuffer[i]);
+	}
+	LOG_MSG_INFO("End of Read buffer.");
+
+	if(0 != memcmp((const void *)pPacketReceiveBuffer,
+	               (const void *)(pA2NDUNPacket + (nBytesSent - nBytesReceived)),
+	               nBytesReceived)) {
+	  LOG_MSG_ERROR("Memory contains don't match");
+	  bTestResult = false;
+	  goto bail;
+	}
+/* fall through */
+
+bail:
+
+	delete pA2NDUNPacket;
+	return bTestResult;
+}
+
+HeaderRemovalMetaDataFiltering::HeaderRemovalMetaDataFiltering()
+{
+	m_name = "HeaderRemovalMetaDataFiltering";
+	m_description =
+			"HeaderRemovalMetaDataFiltering: check meta data based filtering";
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool HeaderRemovalMetaDataFiltering::Run()
+{
+	bool bTestResult = true;
+	Byte pPacketReceiveBuffer[HEADER_REMOVAL_TEST_MAX_PACKET_BYTE_SIZE] = {0};//This buffer will be used in order to store the received packet.
+
+	unsigned int nMagicNumber          = 0x12345678; //arbitrary number
+	unsigned int nChannelID            = 0xABCD;//arbitrary number
+	unsigned int nA2NDUNPacketByteSize = 0;
+	unsigned int nMetaData             = 0;
+	unsigned int nMetaDataMask         = 0xFFFF;
+	unsigned int nBytesSent            = 0;
+	int          nBytesReceived        = 0;
+
+
+	Byte *pA2NDUNPacket = CreateA2NDUNPacket(nMagicNumber, nChannelID, IPV4_FILE_PATH, &nA2NDUNPacketByteSize);
+	if(0 == pA2NDUNPacket) {
+		LOG_MSG_ERROR("Cannot load file to memory, exiting");
+		return false;
+	}
+
+	nMetaData             = (nChannelID << 16) | (0xFFFF & nA2NDUNPacketByteSize);
+	LOG_MSG_INFO("*************nMetaData ==  (0x%x)", nMetaData);
+
+	LOG_MSG_INFO("A2 Packet was  successfully created (%d bytes)", nA2NDUNPacketByteSize);
+
+	SetRoutingTableToPassAllToSpecificClient(IPA_CLIENT_TEST_CONS);
+	SetHeaderInsertionTableAddEmptyHeaderForTheClient(IPA_CLIENT_TEST_CONS);
+
+	LOG_MSG_INFO("Configuring Filtering module...");
+
+	if (false ==
+			ConfigureFilteringBlockWithMetaDataEq(
+					IPA_CLIENT_TEST_CONS,
+					nMetaData,
+					nMetaDataMask)) {
+		bTestResult = false;
+		goto bail;
+	}
+
+	LOG_MSG_INFO("Sending packet into the A2NDUN pipe(%d bytes) and the Pipe will add an header",
+	             nA2NDUNPacketByteSize);
+	nBytesSent = m_A2NDUNToIpaPipe.Send(pA2NDUNPacket, nA2NDUNPacketByteSize);
+	if (nA2NDUNPacketByteSize != nBytesSent) {
+		bTestResult = false;
+		goto bail;
+	}
+
+	//Receive the raw IP packet(which is a 4 arbitrary bytes) without header removal by the Pipe
+	LOG_MSG_INFO("Reading packet from the USB pipe");
+	nBytesReceived = m_IpaToUsbPipe.Receive(pPacketReceiveBuffer, HEADER_REMOVAL_TEST_MAX_PACKET_BYTE_SIZE);
+	//TODO Header Removal: at this point the success scenario is that data came to the correct pipe - change this to
+	//packet memory compare after header insertion is enabled.
+	if (0 == nBytesReceived) {
+		bTestResult = false;
+		goto bail;
+	}
+
+	LOG_MSG_INFO("Read buffer : ");
+	//Print the output
+	for (int i = 0 ; i < nBytesReceived ; i++) {
+	  printf("0x%02x", pPacketReceiveBuffer[i]);
+	}
+	LOG_MSG_INFO("End of Read buffer.");
+
+	if(0 != memcmp((const void *)pPacketReceiveBuffer,
+	               (const void *)(pA2NDUNPacket + (nBytesSent - nBytesReceived)),
+	               nBytesReceived)) {
+	  LOG_MSG_ERROR("Memory contains don't match");
+	  bTestResult = false;
+	  goto bail;
+	}
+
+/* fall through */
+
+bail:
+
+	delete pA2NDUNPacket;
+	return bTestResult;
+}
+
+static HeaderRemovalTOSCheck          headerRemovalTOSCheck;
+static HeaderRemovalMetaDataFiltering headerRemovalMetaDataFiltering;
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+

+ 73 - 0
kernel-tests/HeaderRemovalTests.h

@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _IPA_LINUX_TESTS_HR_TESTS_H_
+#define _IPA_LINUX_TESTS_HR_TESTS_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "Constants.h"
+#include "linux/msm_ipa.h"
+#include "TestsUtils.h"
+#include "HeaderRemovalTestFixture.h"
+
+/*This test will send a DMUX with IP packet and check it TOS field thus
+ *validating the the header was removed.
+ */
+class HeaderRemovalTOSCheck:public HeaderRemovalTestFixture
+{
+public:
+	/*This Constructor will be use to specify some test description.*/
+	HeaderRemovalTOSCheck();
+
+	/*This method will send a an IP packet with
+	 * DMUX header and create a rule
+	 * */
+	virtual bool Run();
+};
+
+/*This test will send a DMUX with IP packet and see if it filtered
+ *by meta data contained in link layer header as expected
+ */
+class HeaderRemovalMetaDataFiltering:HeaderRemovalTestFixture
+{
+public:
+	/* his Constructor will be use to specify
+	 * some test description.*/
+	HeaderRemovalMetaDataFiltering();
+
+	virtual bool Run();
+
+};
+
+#endif

+ 274 - 0
kernel-tests/IPAFilteringTable.cpp

@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "IPAFilteringTable.h"
+#include <cstring>
+#include "TestsUtils.h"
+
+IPAFilteringTable::IPAFilteringTable () : // C'tor
+			m_pFilteringTable(NULL),
+				nextRuleIndex(0) {}
+
+bool IPAFilteringTable::Init(ipa_ip_type ipFamily, ipa_client_type pipeNo, uint8_t isGlobal, uint8_t numOfRulesInTable, uint8_t commit)
+{
+	if (NULL != m_pFilteringTable) {
+		char message[256] = {0};
+		snprintf(message, sizeof(message), "Error in Function %s, m_pFilteringTable==0x%p, must be NULL, Please call D'tor prior to calling () %s.",
+				__FUNCTION__,m_pFilteringTable,__FUNCTION__);
+		ReportError(message);
+		return false;
+	}
+
+	if (numOfRulesInTable < 1) {
+		char message[256] = {0};
+		snprintf(message, sizeof(message),"Error in Function %s, numberOfRulesInTable==%d must be  > 0",
+				__FUNCTION__,numOfRulesInTable);
+		ReportError(message);
+		return false;
+	}
+
+	m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+		calloc(1, sizeof(struct ipa_ioc_add_flt_rule) +
+				numOfRulesInTable *sizeof(struct ipa_flt_rule_add));
+
+	if (NULL ==  m_pFilteringTable) {
+		char message[256] = {0};
+		snprintf(message, sizeof(message),"Error in Function %s, Failed to allocate %d filter rules in Filtering Table",__FUNCTION__,numOfRulesInTable);
+		ReportError(message);
+		return false;
+	}
+
+	m_pFilteringTable->commit = commit;
+	m_pFilteringTable->ep = pipeNo;
+	m_pFilteringTable->global = isGlobal;
+	m_pFilteringTable->ip = ipFamily;
+	m_pFilteringTable->num_rules = (uint8_t)(numOfRulesInTable);
+
+	return true;
+}
+
+bool IPAFilteringTable::GeneratePresetRule(uint8_t preset,ipa_flt_rule_add &flt_rule_entry)
+{
+	memset(&flt_rule_entry,0,sizeof(ipa_flt_rule_add)); // Zero All Fields
+
+	switch (preset)
+	{
+	case 0: // in Preset 0 the Filtering Rule is matches all (bypass)
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		break;
+	case 1:
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl=-1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action=IPA_PASS_TO_ROUTING;
+		//flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_PROTOCOL;
+		flt_rule_entry.rule.attrib.u.v4.protocol = 17; // Filter only UDP Packets.
+		break;
+	default:
+		char message[256] = {0};
+		snprintf(message, sizeof(message),"Error in Function %s, preset=%d, is not supported.",__FUNCTION__,preset);
+		ReportError(message);
+		return false;
+	}
+	return true;
+}
+
+uint8_t IPAFilteringTable::AddRuleToTable(ipa_flt_rule_add flt_rule_entry)
+{
+	if (NULL == m_pFilteringTable) {
+		char message[256] = {0};
+		snprintf(message, sizeof(message),"Error in Function %s, m_pFilteringTable==NULL, Please call Init() prior to calling %s().",__FUNCTION__,__FUNCTION__);
+		ReportError(message);
+		return -1;
+	}
+
+	if (nextRuleIndex >= m_pFilteringTable->num_rules) {
+		char message[256] = {0};
+		snprintf(message, sizeof(message),"Error in Function %s, ruleIindex==%d while, No. of Rules in Filtering Table is %d. Please use IPAFilteringTable::WriteRule().",
+				__FUNCTION__,nextRuleIndex,m_pFilteringTable->num_rules);
+		ReportError(message);
+		return -1;
+	}
+	struct ipa_flt_rule_add *pFilteringRule = &(m_pFilteringTable->rules[nextRuleIndex]);
+	memcpy(pFilteringRule,&flt_rule_entry,sizeof(ipa_flt_rule_add));
+	nextRuleIndex++;
+	return(nextRuleIndex-1);
+}
+
+const ipa_flt_rule_add * IPAFilteringTable::ReadRuleFromTable(uint8_t index)
+{
+	if (index < nextRuleIndex)
+		return (&(m_pFilteringTable->rules[index]));
+	return NULL;
+}
+
+// Function Not Implemented - Always returns FALSE
+bool IPAFilteringTable::WriteRuleToTable(uint8_t index,ipa_flt_rule_add flt_rule_entry) {return false;}
+
+//This Function Frees the Filtering Table and all it's content.
+//This Function will always return TRUE;
+void IPAFilteringTable::Destructor()
+{
+	if (NULL != m_pFilteringTable) {
+		free (m_pFilteringTable);
+		printf("Filtering Table Freed\n");
+	}
+	m_pFilteringTable = NULL;
+	nextRuleIndex = 0;
+}
+
+IPAFilteringTable::~IPAFilteringTable()
+{
+	Destructor();
+}
+
+/* V2 */
+
+IPAFilteringTable_v2::IPAFilteringTable_v2() : // C'tor
+	m_pFilteringTable_v2(NULL),
+	nextRuleIndex(0)
+{
+}
+
+bool IPAFilteringTable_v2::Init(ipa_ip_type ipFamily, ipa_client_type pipeNo, uint8_t isGlobal, uint8_t numOfRulesInTable, uint8_t commit)
+{
+	if (NULL != m_pFilteringTable_v2) {
+		char message[256] = { 0 };
+		snprintf(message, sizeof(message), "Error in Function %s, m_pFilteringTable_v2==0x%p, must be NULL, Please call D'tor prior to calling () %s.",
+			__FUNCTION__, m_pFilteringTable_v2, __FUNCTION__);
+		ReportError(message);
+		return false;
+	}
+
+	if (numOfRulesInTable < 1) {
+		char message[256] = { 0 };
+		snprintf(message, sizeof(message), "Error in Function %s, numberOfRulesInTable==%d must be  > 0",
+			__FUNCTION__, numOfRulesInTable);
+		ReportError(message);
+		return false;
+	}
+
+	m_pFilteringTable_v2 = (struct ipa_ioc_add_flt_rule_v2 *)
+		calloc(1, sizeof(struct ipa_ioc_add_flt_rule_v2));
+	m_pFilteringTable_v2->rules = (uint64_t)calloc(numOfRulesInTable, sizeof(struct ipa_flt_rule_add_v2));
+
+	if (NULL == m_pFilteringTable_v2) {
+		char message[256] = { 0 };
+		snprintf(message, sizeof(message), "Error in Function %s, Failed to allocate %d filter rules in Filtering Table V2", __FUNCTION__, numOfRulesInTable);
+		ReportError(message);
+		return false;
+	}
+
+	m_pFilteringTable_v2->commit = commit;
+	m_pFilteringTable_v2->ep = pipeNo;
+	m_pFilteringTable_v2->global = isGlobal;
+	m_pFilteringTable_v2->ip = ipFamily;
+	m_pFilteringTable_v2->num_rules = (uint8_t)(numOfRulesInTable);
+	m_pFilteringTable_v2->flt_rule_size = sizeof(struct ipa_flt_rule_add_v2);
+	return true;
+}
+
+bool IPAFilteringTable_v2::GeneratePresetRule(uint8_t preset, ipa_flt_rule_add_v2 &flt_rule_entry)
+{
+	memset(&flt_rule_entry, 0, sizeof(ipa_flt_rule_add_v2)); // Zero All Fields
+
+	switch (preset) {
+	case 0: // in Preset 0 the Filtering Rule is matches all (bypass)
+		flt_rule_entry.flt_rule_hdl = -1; // return Value
+		flt_rule_entry.status = -1; // return value
+		break;
+	case 1:
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+		//flt_rule_entry.rule.rt_tbl_hdl=routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_PROTOCOL;
+		flt_rule_entry.rule.attrib.u.v4.protocol = 17; // Filter only UDP Packets.
+		break;
+	default:
+		char message[256] = { 0 };
+		snprintf(message, sizeof(message), "Error in Function %s, preset=%d, is not supported.", __FUNCTION__, preset);
+		ReportError(message);
+		return false;
+	}
+	return true;
+}
+
+uint8_t IPAFilteringTable_v2::AddRuleToTable(ipa_flt_rule_add_v2 flt_rule_entry)
+{
+	if (NULL == m_pFilteringTable_v2) {
+		char message[256] = { 0 };
+		snprintf(message, sizeof(message), "Error in Function %s, m_pFilteringTable_v2==NULL, Please call Init() prior to calling %s().", __FUNCTION__, __FUNCTION__);
+		ReportError(message);
+		return -1;
+	}
+
+	if (nextRuleIndex >= m_pFilteringTable_v2->num_rules) {
+		char message[256] = { 0 };
+		snprintf(message, sizeof(message), "Error in Function %s, ruleIindex==%d while, No. of Rules in Filtering Table is %d. Please use IPAFilteringTable::WriteRule().",
+			__FUNCTION__, nextRuleIndex, m_pFilteringTable_v2->num_rules);
+		ReportError(message);
+		return -1;
+	}
+	struct ipa_flt_rule_add_v2 *pFilteringRule = &(((struct ipa_flt_rule_add_v2 *)(m_pFilteringTable_v2->rules))[nextRuleIndex]);
+	memcpy(pFilteringRule, &flt_rule_entry, sizeof(ipa_flt_rule_add_v2));
+	nextRuleIndex++;
+	return(nextRuleIndex - 1);
+}
+
+const ipa_flt_rule_add_v2 *IPAFilteringTable_v2::ReadRuleFromTable(uint8_t index)
+{
+	if (index < nextRuleIndex)
+		return (&(((struct ipa_flt_rule_add_v2*)m_pFilteringTable_v2->rules)[index]));
+	return NULL;
+}
+
+// Function Not Implemented - Always returns FALSE
+bool IPAFilteringTable_v2::WriteRuleToTable(uint8_t index, ipa_flt_rule_add_v2 flt_rule_entry) { return false; }
+
+//This Function Frees the Filtering Table and all it's content.
+//This Function will always return TRUE;
+void IPAFilteringTable_v2::Destructor()
+{
+	if (NULL != m_pFilteringTable_v2) {
+		free(m_pFilteringTable_v2);
+		printf("Filtering Table Freed\n");
+	}
+	m_pFilteringTable_v2 = NULL;
+	nextRuleIndex = 0;
+}
+
+IPAFilteringTable_v2::~IPAFilteringTable_v2()
+{
+	Destructor();
+}
+

+ 149 - 0
kernel-tests/IPAFilteringTable.h

@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FILTERING_TABLE_
+#define _FILTERING_TABLE_
+
+#include "Constants.h"
+#include "Filtering.h"
+
+
+/*This Class Encapsulate Filtering Table and Filtering Rules.
+ *It allows the user to easily manipulate rules and Tables.
+ */
+class IPAFilteringTable
+{
+public:
+	IPAFilteringTable();
+	~IPAFilteringTable();
+
+	bool Init(ipa_ip_type ipFamily,
+			ipa_client_type pipeNo,
+			uint8_t isGlobal,
+			uint8_t numOfRulesInTable,
+			uint8_t commit = true);
+
+	/*This Function Frees the Filtering Table and all it's content.
+	 *This Function will always return TRUE;
+	 */
+	void Destructor();
+
+
+	bool GeneratePresetRule(
+			uint8_t preset,
+			ipa_flt_rule_add & flt_rule_entry);
+	bool GeneratePresetRule(
+			uint8_t preset,
+			ipa_flt_rule_add_v2 &flt_rule_entry);
+	uint8_t AddRuleToTable(
+			ipa_flt_rule_add flt_rule_entry);
+	uint8_t AddRuleToTable(
+			ipa_flt_rule_add_v2 flt_rule_entry);
+	bool WriteRuleToTable(
+			uint8_t index,
+			ipa_flt_rule_add flt_rule_entry);
+
+	/*Warning!!!
+	 *Take care when using this function.
+	 *The Returned pointer existence is guaranteed only as
+	 *long as no other method of this class is called.
+	 */
+	const ipa_flt_rule_add *ReadRuleFromTable(uint8_t index);
+
+	/*Warning!!!
+	 *Take care when using this function
+	 *The Returned pointer existence is guaranteed only
+	 *as long as no other method of this class is called.
+	 */
+	const ipa_ioc_add_flt_rule *GetFilteringTable()
+	{
+		return m_pFilteringTable;
+	}
+
+private:
+	void ReportError(char *message)
+	{
+		printf("%s\n", message);
+	}
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+	uint8_t nextRuleIndex;
+};
+
+class IPAFilteringTable_v2 {
+public:
+	IPAFilteringTable_v2();
+	~IPAFilteringTable_v2();
+
+	bool Init(ipa_ip_type ipFamily,
+		ipa_client_type pipeNo,
+		uint8_t isGlobal,
+		uint8_t numOfRulesInTable,
+		uint8_t commit = true);
+
+	/*This Function Frees the Filtering Table and all it's content.
+	 *This Function will always return TRUE;
+	 */
+	void Destructor();
+
+	bool GeneratePresetRule(
+		uint8_t preset,
+		ipa_flt_rule_add_v2 &flt_rule_entry);
+	uint8_t AddRuleToTable(
+		ipa_flt_rule_add_v2 flt_rule_entry);
+	bool WriteRuleToTable(
+		uint8_t index,
+		ipa_flt_rule_add_v2 flt_rule_entry);
+
+	/*Warning!!!
+	 *Take care when using this function.
+	 *The Returned pointer existence is guaranteed only as
+	 *long as no other method of this class is called.
+	 */
+	const ipa_flt_rule_add_v2 *ReadRuleFromTable(uint8_t index);
+
+	/*Warning!!!
+	 *Take care when using this function
+	 *The Returned pointer existence is guaranteed only
+	 *as long as no other method of this class is called.
+	 */
+	const ipa_ioc_add_flt_rule_v2 *GetFilteringTable()
+	{
+		return m_pFilteringTable_v2;
+	}
+
+private:
+	void ReportError(char *message)
+	{
+		printf("%s\n", message);
+	}
+	ipa_ioc_add_flt_rule_v2 *m_pFilteringTable_v2;
+	uint8_t nextRuleIndex;
+};
+
+#endif

+ 93 - 0
kernel-tests/IPAInterruptsTestFixture.cpp

@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "IPAInterruptsTestFixture.h"
+
+/*define the static Pipes which will be used by all derived tests.*/
+Pipe IPAInterruptsTestFixture::m_IpaToUsbPipe(IPA_CLIENT_TEST_CONS, IPA_TEST_CONFIGURATION_19);
+Pipe IPAInterruptsTestFixture::m_UsbToIpaPipe(IPA_CLIENT_TEST_PROD, IPA_TEST_CONFIGURATION_19);
+
+IPAInterruptsTestFixture::IPAInterruptsTestFixture()
+{
+	m_testSuiteName.push_back("Interrupts");
+}
+
+bool IPAInterruptsTestFixture::Setup()
+{
+	return true;
+}
+
+bool IPAInterruptsTestFixture::Run()
+{
+	bool bTestResult = true;
+	Byte pIpPacket[] = { 0x01, 0x02, 0x03, 0x04 }; //This packet will be sent(It can be replaced by a real IP packet).
+	Byte pIpPacketReceive[sizeof(pIpPacket)] = { 0 }; //This buffer will be used in order to store the received packet.
+
+	//Send the raw IP packet(which is a 4 arbitrary bytes) without header addition by the Pipe
+	LOG_MSG_DEBUG(
+			"Sending packet into the USB pipe(%d bytes)\n", sizeof(pIpPacket));
+	int nBytesSent = m_UsbToIpaPipe.Send(pIpPacket, sizeof(pIpPacket));
+	if (sizeof(pIpPacket) != nBytesSent) {
+		return false;
+	}
+
+	//Receive the raw IP packet(which is a 4 arbitrary bytes) without header removal by the Pipe
+	LOG_MSG_DEBUG(
+			"Reading packet from the USB pipe(%d bytes should be there)\n", sizeof(pIpPacketReceive));
+	int nBytesReceived = m_IpaToUsbPipe.Receive(pIpPacketReceive,
+			sizeof(pIpPacketReceive));
+	if (sizeof(pIpPacketReceive) != nBytesReceived) {
+		LOG_MSG_DEBUG("sizes mismatch\n");
+		for (int i = 0; i < nBytesReceived && i < (int)sizeof(pIpPacketReceive) ; i++) {
+			LOG_MSG_DEBUG("0x%02x\n", pIpPacketReceive[i]);
+		}
+		return false;
+	}
+	for (int i = 0; i < nBytesReceived; i++) {
+		LOG_MSG_DEBUG("0x%02x\n", pIpPacketReceive[i]);
+	}
+
+	//Check that the sent IP packet is equal to the received IP packet.
+	LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+	bTestResult &= !memcmp(pIpPacket, pIpPacketReceive, sizeof(pIpPacket));
+
+	return bTestResult;
+}
+
+bool IPAInterruptsTestFixture::Teardown()
+{
+	/* unregister the test framework suspend handler */
+	RegSuspendHandler(false, false, 0);
+
+	/*The Destroy method will close the inode.*/
+	m_IpaToUsbPipe.Destroy();
+	m_UsbToIpaPipe.Destroy();
+	ConfigureScenario(-1);
+	return true;
+}

+ 72 - 0
kernel-tests/IPAInterruptsTestFixture.h

@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "Constants.h"
+#include "Logger.h"
+#include "linux/msm_ipa.h"
+#include "TestsUtils.h"
+#include "TestBase.h"
+#include "Pipe.h"
+
+/*This class will be the base class of all Pipe tests.
+ *Any method other than the test case itself can be
+ *declared in this Fixture thus allowing the derived classes to
+ *implement only the test case.
+ *All the test of the pipe uses one input and one output in DMA mode.
+ */
+class IPAInterruptsTestFixture:public TestBase
+{
+public:
+	/*This Constructor will register each instance that it creates.*/
+	IPAInterruptsTestFixture();
+
+	/*This method will create and initialize two Pipe object for the USB
+	 * (Ethernet) Pipes, one as input and the other as output.
+	 */
+	virtual bool Setup();
+
+	/*Run test logic*/
+	bool Run();
+
+	/*This method will destroy the pipes.*/
+	virtual bool Teardown();
+
+	/*The client type are set from the peripheral perspective
+	 * (TODO Pipe:in case the Driver will change its perspective
+	 * of ipa_connect this should be changed).
+	 */
+	static Pipe m_IpaToUsbPipe;
+	static Pipe m_UsbToIpaPipe;
+};

+ 104 - 0
kernel-tests/IPAInterruptsTests.cpp

@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "IPAInterruptsTestFixture.h"
+#include "Constants.h"
+#include "TestsUtils.h"
+#include "linux/msm_ipa.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class SuspendTestDeferred: public IPAInterruptsTestFixture {
+public:
+
+	SuspendTestDeferred() {
+		m_name = "SuspendTestDeferred";
+		m_description = "This test will send data on a suspended pipe(Deferred context) ";
+		Register(*this);
+	}
+
+	bool Setup()
+	{
+		bool bRetVal = true;
+
+		/*Set the configuration to support USB->IPA and IPA->USB pipes.*/
+		ConfigureScenario(IPA_TEST_CONFIGURATION_19);
+
+		RegSuspendHandler(true,true,0);
+
+		/*Initialize the pipe for all the tests -
+		 * this will open the inode which represents the pipe.
+		 */
+		bRetVal &= m_IpaToUsbPipe.Init();
+		bRetVal &= m_UsbToIpaPipe.Init();
+		return bRetVal;
+	}
+};
+
+
+class SuspendTest: public IPAInterruptsTestFixture {
+public:
+
+	SuspendTest() {
+		m_name = "SuspendTest";
+		m_description = "This test will send data on a suspended pipe";
+		Register(*this);
+	}
+
+	bool Setup()
+	{
+		bool bRetVal = true;
+
+		/*Set the configuration to support USB->IPA and IPA->USB pipes.*/
+		ConfigureScenario(IPA_TEST_CONFIGURATION_19);
+
+		RegSuspendHandler(false,true,0);
+
+		/*Initialize the pipe for all the tests -
+		 * this will open the inode which represents the pipe.
+		 */
+		bRetVal &= m_IpaToUsbPipe.Init();
+		bRetVal &= m_UsbToIpaPipe.Init();
+		return bRetVal;
+	}
+};
+
+static SuspendTest suspendTest;
+static SuspendTestDeferred suspendTestDeferred;
+/////////////////////////////////////////////////////////////////////////////////
+//                                  EOF                                      ////
+/////////////////////////////////////////////////////////////////////////////////

+ 409 - 0
kernel-tests/IPv4Packet.cpp

@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "TestsUtils.h"
+#include "IPv4Packet.h"
+#include "memory.h"
+
+using namespace IPA;
+
+static const unsigned char TCP_IP_PACKET_DUMP[] = { 0x45, // IPv4, IHL = 5
+		0x00, // ToS = 0
+		0x00, 0x28, // Total length
+		0x11, 0xc2, // ID
+		0x40, 0x00, //ID + Fragment Offset
+		0x80, // TTL
+		0x06, // Protocol = TCP
+		0x70, 0x3a, //Checksum
+		0x0a, 0x05, 0x07, 0x46, // Source IP 10.5.7.70
+		0x81, 0x2e, 0xe6, 0x5a, // Destination IP 129.46.230.90
+		0xf3, 0xa2, // Source Port  62370
+		0x01, 0xbd, // Destination Port 445
+		0x26, 0x26, 0x1d, 0x7d, // Seq Number
+		0x15, 0xaa, 0xbc, 0xdb, // Ack Num
+		0x50, 0x10, 0x80, 0xd4, // TCP Params
+		0xaa, 0xa3, // TCP Checksum
+		0x00, 0x00 // Urgent PTR
+		};
+
+static const unsigned char UDP_IP_PACKET_DUMP[] = {
+		0x45, // IPv4, IHL = 5
+		0x00, // ToS = 0
+		0x00,
+		0x34, // Total Length
+		0x12,
+		0xa2, // ID
+		0x00,
+		0x00, //ID + fragment offset
+		0x80, // TTL
+		0x11, // Protocol = UDP
+		0xe4,
+		0x92, // Checksum
+		0x0a, 0x05, 0x07,
+		0x46, // Source IP 10.5.7.70
+		0x0a, 0x2b, 0x28,
+		0x0f, // Destination IP 10.43.40.15
+		0x03,
+		0x4a, // Source port 842
+		0x1b,
+		0x4f, // Destination Port 6991
+		0x00,
+		0x20, // UDP length
+		0x36,
+		0xac, // UDP checksum
+		0x00, 0x05, 0x20,
+		0x6d, // Data
+		0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x01, 0x13, 0x05, 0x20, 0x6c };
+static unsigned char ICMP_IP_PACKET_DUMP[] = {
+		//IP
+		0x45, 0x00, 0x00, 0xdc, 0x03, 0xfe, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+		0x81, 0x2e, 0xe4, 0xf6, 0x81, 0x2e, 0xe6, 0xd4,
+		//ICMP
+		0x00, 0x00, 0xa9, 0xcd, 0x28, 0xa3, 0x01, 0x00,
+		//DATA
+		0xee, 0x7c, 0xf7, 0x90, 0x39, 0x06, 0xd4, 0x41, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+		0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51 };
+
+static void LittleToBigEndianUint32(unsigned char *pBigEndianBuffer,
+		unsigned int nUint32LittleEndianValue) {
+	unsigned char nLsb = nUint32LittleEndianValue & 0xff;
+	unsigned char nLsbMsbLow = (nUint32LittleEndianValue >> 8) & 0xff;
+	unsigned char nLsbMsbHigh = (nUint32LittleEndianValue >> 16) & 0xff;
+	unsigned char nMsb = (nUint32LittleEndianValue >> 24) & 0xff;
+
+	pBigEndianBuffer[0] = nMsb;
+	pBigEndianBuffer[1] = nLsbMsbHigh;
+	pBigEndianBuffer[2] = nLsbMsbLow;
+	pBigEndianBuffer[3] = nLsb;
+}
+
+static unsigned short BigToLittleEndianUint16(unsigned char *pBigEndianStart) {
+	unsigned char nMsb = pBigEndianStart[0];
+	unsigned char nLsb = pBigEndianStart[1];
+
+	return (nMsb << 8 | nLsb << 0);
+}
+
+static unsigned int BigToLittleEndianUint32(unsigned char *pBigEndianStart) {
+	unsigned char nMsb = pBigEndianStart[0];
+	unsigned char nMsbLsbHigh = pBigEndianStart[1];
+	unsigned char nMsbLsbLow = pBigEndianStart[2];
+	unsigned char nLsb = pBigEndianStart[3];
+
+	return (nMsb << 24 | nMsbLsbHigh << 16 | nMsbLsbLow << 8 | nLsb << 0);
+}
+
+static void LittleToBigEndianUint16(unsigned char *pBigEndianBuffer,
+		unsigned int nUint16LittleEndianValue) {
+	unsigned char nLsb = nUint16LittleEndianValue & 0xff;
+	unsigned char nMsb = (nUint16LittleEndianValue >> 8) & 0xff;
+
+	pBigEndianBuffer[0] = nMsb;
+	pBigEndianBuffer[1] = nLsb;
+}
+
+static unsigned short Get2BBIGEndian(const unsigned char *pBuff, int offset) {
+	unsigned char upperByte = 0;
+	unsigned char lowerByte = 0;
+
+	memcpy(&upperByte, pBuff + offset, 1);
+	memcpy(&lowerByte, pBuff + offset + 1, 1);
+
+	return (upperByte << 8 | lowerByte);
+}
+
+IPv4Packet::IPv4Packet(unsigned int size) :
+		m_PacketSize(size) {
+}
+
+IPv4Packet::~IPv4Packet(void) {
+	if (0 != m_Packet) {
+		delete[] m_Packet;
+		m_Packet = 0;
+	}
+}
+
+void IPv4Packet::ToNetworkByteStream(unsigned char *buffer) {
+	if (0 == buffer) {
+		LOG_MSG_ERROR("IPv4Packet::ToNetworkByteStream : NULL arguments");
+		return;
+	}
+
+	memcpy(buffer, m_Packet, GetSize());
+}
+
+unsigned int IPv4Packet::GetSrcAddr(void) {
+	return BigToLittleEndianUint32(m_Packet + 12);
+}
+
+void IPv4Packet::SetSrcAddr(unsigned int addr) {
+	LittleToBigEndianUint32(m_Packet + 12, addr);
+	RecalculateChecksum();
+}
+
+unsigned int IPv4Packet::GetDstAddr(void) {
+
+	return BigToLittleEndianUint32(m_Packet + 16);
+}
+
+void IPv4Packet::SetDstAddr(unsigned int addr) {
+	LittleToBigEndianUint32(m_Packet + 16, addr);
+	RecalculateChecksum();
+}
+
+unsigned char IPv4Packet::GetProtocol(void) {
+	unsigned char retVal = 0;
+	memcpy(&retVal, m_Packet + 9, sizeof(unsigned char));
+	return retVal;
+}
+
+unsigned short IPv4Packet::GetSrcPort(void) {
+	return BigToLittleEndianUint16(m_Packet + 20);
+}
+
+unsigned short IPv4Packet::GetDstPort(void) {
+	return BigToLittleEndianUint16(m_Packet + 22);
+}
+
+void IPv4Packet::SetDstPort(unsigned short port) {
+
+	LittleToBigEndianUint16(m_Packet + 22, port);
+	RecalculateChecksum();
+}
+
+void IPv4Packet::SetSrcPort(unsigned short port) {
+	LittleToBigEndianUint16(m_Packet + 20, port);
+	RecalculateChecksum();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+//Set the third MSB bit of the IPV4_FLAGS_BYTE_OFFSET's byte
+void IPv4Packet::SetMF(bool bValue) {
+
+	Byte * pFlags = m_Packet + IPV4_FLAGS_BYTE_OFFSET;
+	//clear the bit
+	if (true == bValue)	{
+		*pFlags |= (0x20);
+	} else {
+		*pFlags &= (~0x20);
+	}
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void IPv4Packet::RecalculateChecksum(void) {
+	RecalculateIPChecksum();
+	RecalculateTCPChecksum();
+	RecalculateUDPChecksum();
+}
+
+void IPv4Packet::RecalculateIPChecksum(void) {
+	unsigned short pUint16[100];
+	int headerLen = (m_Packet[0] & 0x0F) * 2;
+	int checksum = 0;
+	unsigned short result = 0;
+
+	memset(&pUint16, 0, 100 * sizeof(unsigned short));
+
+	//clear the IP checksum field first
+	memset(m_Packet + 10, 0, sizeof(unsigned short));
+
+	memcpy(&pUint16, m_Packet, headerLen * sizeof(unsigned short));
+
+	for (int i = 0; i < headerLen; i++) {
+		checksum += pUint16[i];
+		checksum = (checksum & 0xFFFF) + (checksum >> 16);
+	}
+
+	result = (~checksum & 0xFFFF);
+
+	memcpy(m_Packet + 10, &result, sizeof(unsigned short));
+
+	return;
+}
+
+void TCPPacket::RecalculateTCPChecksum(void) {
+	unsigned short *pUint16 = new unsigned short[100];
+	int checksum = 0;
+	int headerLen = 0;
+	unsigned short *pTemp = 0;
+	unsigned short result = 0;
+
+	headerLen = Get2BBIGEndian(m_Packet, 2) - (m_Packet[0] & 0x0F) * 4;
+
+	memset(pUint16, 0, 100);
+
+	//clear the TCP checksum field first
+	memset(m_Packet + 36, 0, sizeof(unsigned short));
+
+	memcpy(pUint16, m_Packet, headerLen * sizeof(unsigned short));
+
+	pTemp = pUint16;
+
+	// Pseudo Header
+	pUint16 += 6; // Source IP
+	for (int i = 0; i < 4; i++) {
+		checksum += pUint16[i];
+		checksum = (checksum & 0xFFFF) + (checksum >> 16);
+	}
+
+	checksum += 0x0600; // TCP Protocol
+	checksum += Get2BBIGEndian((unsigned char*) &headerLen, 0);
+
+	pUint16 = pTemp + (m_Packet[0] & 0x0F) * 2;
+	headerLen /= 2;
+	for (int i = 0; i < headerLen; i++) {
+		checksum += pUint16[i];
+		checksum = (checksum & 0xFFFF) + (checksum >> 16);
+	}
+
+	result = (~checksum & 0xFFFF);
+
+	memcpy(m_Packet + 36, &result, sizeof(unsigned short));
+
+	delete[] pTemp;
+
+	return;
+}
+
+void UDPPacket::RecalculateUDPChecksum(void) {
+	unsigned short *pUint16 = new unsigned short[100];
+	int checksum = 0;
+	int headerLen = 0;
+	unsigned short *pTemp = 0;
+	unsigned short result = 0;
+
+	headerLen = Get2BBIGEndian(m_Packet, (m_Packet[0] & 0x0F) * 4 + 4);
+
+	memset(pUint16, 0, 100);
+
+	//clear the UDP checksum field first
+	memset(m_Packet + 26, 0, sizeof(unsigned short));
+
+	memcpy(pUint16, m_Packet, headerLen * sizeof(unsigned short));
+
+	pTemp = pUint16;
+
+	// Pseudo Header
+	pUint16 += 6; // Source IP
+	for (int i = 0; i < 4; i++) {
+		checksum += pUint16[i];
+		checksum = (checksum & 0xFFFF) + (checksum >> 16);
+	}
+
+	checksum += 0x1100; // UDP Protocol
+	checksum += Get2BBIGEndian((unsigned char*) &headerLen, 0);
+
+	pUint16 = pTemp + (m_Packet[0] & 0x0F) * 2;
+	headerLen /= 2;
+	for (int i = 0; i < headerLen; i++) {
+		checksum += pUint16[i];
+		checksum = (checksum & 0xFFFF) + (checksum >> 16);
+	}
+
+	result = (~checksum & 0xFFFF);
+
+	memcpy(m_Packet + 26, &result, sizeof(unsigned short));
+
+	delete[] pTemp;
+	return;
+}
+
+TCPPacket::TCPPacket(void) :
+		IPv4Packet(sizeof(TCP_IP_PACKET_DUMP)) {
+	size_t length = GetSize();
+
+	m_Packet = new unsigned char[length];
+	if (0 == m_Packet) {
+		LOG_MSG_ERROR("TCPPacket : packet allocation failed");
+		return;
+	}
+
+	memcpy(m_Packet, TCP_IP_PACKET_DUMP, length);
+}
+
+UDPPacket::UDPPacket(void) :
+		IPv4Packet(sizeof(UDP_IP_PACKET_DUMP)) {
+	size_t length = GetSize();
+
+	m_Packet = new unsigned char[length];
+	if (0 == m_Packet) {
+		LOG_MSG_ERROR("UDPPacket : packet allocation failed");
+		return;
+	}
+
+	memcpy(m_Packet, UDP_IP_PACKET_DUMP, length);
+}
+
+ICMPPacket::ICMPPacket(void) :
+		IPv4Packet(sizeof(ICMP_IP_PACKET_DUMP)) {
+	size_t length = GetSize();
+
+	m_Packet = new unsigned char[length];
+	if (0 == m_Packet) {
+		LOG_MSG_ERROR("ICMPPacket : packet allocation failed");
+		return;
+	}
+
+	memcpy(m_Packet, ICMP_IP_PACKET_DUMP, length);
+}
+
+unsigned short ICMPPacket::GetSrcPort(void) {
+	return 0;
+}
+
+unsigned short ICMPPacket::GetDstPort(void) {
+	return 0;
+}
+
+void ICMPPacket::SetDstPort(unsigned short port) {
+	(void) port;
+	return;
+}
+
+void ICMPPacket::SetSrcPort(unsigned short port) {
+	(void) port;
+	return;
+}

+ 179 - 0
kernel-tests/IPv4Packet.h

@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __IPA_TESTS_IPV4_PACKET__H__
+#define __IPA_TESTS_IPV4_PACKET__H__
+
+namespace IPA
+{
+
+#define IPV4_FLAGS_BYTE_OFFSET 6
+
+/**
+  @brief
+  IPv4Packet abstract class.
+
+  @details
+  new setters should call to RecalculateChecksum();
+  */
+class IPv4Packet
+{
+public:
+
+	IPv4Packet(unsigned int size);
+
+	virtual ~IPv4Packet(void) = 0;
+
+	void ToNetworkByteStream(unsigned char *addr);
+
+	unsigned int GetSrcAddr(void);
+
+	void SetSrcAddr(unsigned int addr);
+
+	unsigned int GetDstAddr(void);
+
+	void SetDstAddr(unsigned int addr);
+
+	unsigned char GetProtocol(void);
+
+	unsigned int GetSize(void)
+	{
+		return m_PacketSize;
+	}
+
+	virtual unsigned short GetSrcPort(void);
+
+	virtual unsigned short GetDstPort(void);
+
+	virtual void SetDstPort(unsigned short port);
+
+	virtual void SetSrcPort(unsigned short port);
+
+	void SetMF(bool bValue);
+
+protected:
+
+	virtual void RecalculateTCPChecksum(void)  {}
+
+	virtual void RecalculateUDPChecksum(void)  {}
+
+	virtual void RecalculateICMPChecksum(void) {}
+
+	unsigned char *m_Packet;
+
+private:
+
+	unsigned int  m_PacketSize;
+
+	void RecalculateChecksum(void);
+
+	void RecalculateIPChecksum(void);
+};
+
+/**
+  @brief
+  TCPPacket implementation.
+
+  @details
+  new setters should call to RecalculateChecksum();
+  */
+class TCPPacket:public IPv4Packet
+{
+public:
+
+	TCPPacket(void);
+
+	~TCPPacket(void) {}
+
+protected:
+
+	virtual void RecalculateTCPChecksum(void);
+};
+
+/**
+  @brief
+  UDPPacket implementation.
+
+  @details
+  new setters should call to RecalculateChecksum();
+  */
+class UDPPacket:public IPv4Packet
+{
+public:
+	UDPPacket(void);
+
+	~UDPPacket(void) {}
+
+protected:
+
+	virtual void RecalculateUDPChecksum(void);
+};
+
+/**
+  @brief
+  ICMPPacket implementation.
+
+  @details
+  new setters should call to RecalculateChecksum();
+  */
+class ICMPPacket:public IPv4Packet
+{
+public:
+	ICMPPacket(void);
+
+	~ICMPPacket(void) {}
+
+	virtual unsigned short GetSrcPort(void);
+
+	virtual unsigned short GetDstPort(void);
+
+	virtual void SetDstPort(unsigned short port);
+
+	virtual void SetSrcPort(unsigned short port);
+
+protected:
+
+	/**
+	@brief
+	RecalculateICMPChecksum method.
+
+	@details
+	ICMP checksum recalculation is not needed now
+	and by so is not implemented yet
+	TODO: implement if needed
+   */
+	virtual void RecalculateICMPChecksum(void)
+	{
+		return;
+	}
+};
+
+} /* namespace IPA */
+
+#endif

+ 1781 - 0
kernel-tests/IPv6CTTest.cpp

@@ -0,0 +1,1781 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <cstring> // for memcpy
+#include "hton.h" // for htonl
+#include "InterfaceAbstraction.h"
+#include "Constants.h"
+#include "Logger.h"
+#include "TestsUtils.h"
+#include "Filtering.h"
+#include "RoutingDriverWrapper.h"
+#include "IPAFilteringTable.h"
+extern "C" {
+#include "ipa_ipv6ct.h"
+}
+
+#define IPV6_SRC_PORT_OFFSET (40)
+#define IPV6_SRC_ADDRESS_MSB_OFFSET (8)
+#define IPV6_SRC_ADDRESS_LSB_OFFSET (16)
+#define IPV6_DST_ADDRESS_MSB_OFFSET (24)
+#define IPV6_DST_ADDRESS_LSB_OFFSET (32)
+#define IPV6_DST_PORT_OFFSET (40+2)
+
+#define IPV6_LOW_32_MASK (0xFFFFFFFF)
+#define IPV6_HIGH_32_MASK (0xFFFFFFFF00000000)
+
+#define IPV6_BITS_IN_BYTE 8
+
+inline uint32_t GetHigh32(uint64_t in)
+{
+	return static_cast<uint32_t>((in & IPV6_HIGH_32_MASK) >> 32);
+}
+
+inline uint32_t GetLow32(uint64_t in)
+{
+	return static_cast<uint32_t>(in & IPV6_LOW_32_MASK);
+}
+
+template <typename T>
+T HostToNetwork(T in)
+{
+	printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+	if (1 == htons(1))
+	{
+		return in;
+	}
+
+	static const T mask = 0xff;
+	T ret;
+	uint8_t* p = reinterpret_cast<uint8_t*>(&ret + 1);
+	while (in)
+	{
+		*--p = static_cast<uint8_t>(in & mask);
+		in >>= IPV6_BITS_IN_BYTE;
+	}
+	printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+	return ret;
+}
+
+extern Logger g_Logger;
+
+class IpaIPv6CTBlockTestFixture : public TestBase
+{
+public:
+
+	IpaIPv6CTBlockTestFixture() :
+		m_sendSize(BUFF_MAX_SIZE),
+		m_sendSize2(BUFF_MAX_SIZE),
+		m_sendSize3(BUFF_MAX_SIZE),
+		m_outbound_dst_addr_msb(0XFF02000000000000),
+		m_outbound_dst_addr_lsb(0x11223344556677AA),
+		m_outbound_dst_port(1000),
+		m_outbound_src_addr_msb(m_outbound_dst_addr_msb),
+		m_outbound_src_addr_lsb(0x11223344556677CC),
+		m_outbound_src_port(1001),
+		m_direction_settings(IPA_IPV6CT_DIRECTION_ALLOW_ALL),
+		m_tableHandle(0)
+	{
+		memset(m_sendBuffer, 0, sizeof(m_sendBuffer));	// First input file / IP packet
+		memset(m_sendBuffer2, 0, sizeof(m_sendBuffer2));	// Second input file / IP packet
+		memset(m_sendBuffer3, 0, sizeof(m_sendBuffer3));	// Third input file (default) / IP packet
+		m_minIPAHwType = IPA_HW_v4_0;
+		m_testSuiteName.push_back("IPv6CT");
+	}
+
+	static int SetupKernelModule(bool en_status = false)
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		int retval;
+		struct ipa_channel_config from_ipa_channels[3];
+		struct test_ipa_ep_cfg from_ipa_cfg[3];
+		struct ipa_channel_config to_ipa_channels[1];
+		struct test_ipa_ep_cfg to_ipa_cfg[1];
+
+		struct ipa_test_config_header header = { 0 };
+		struct ipa_channel_config *to_ipa_array[1];
+		struct ipa_channel_config *from_ipa_array[3];
+
+		/* From ipa configurations - 3 pipes */
+		memset(&from_ipa_cfg[0], 0, sizeof(from_ipa_cfg[0]));
+		prepare_channel_struct(&from_ipa_channels[0],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST2_CONS,
+			(void *)&from_ipa_cfg[0],
+			sizeof(from_ipa_cfg[0]),
+			en_status);
+		from_ipa_array[0] = &from_ipa_channels[0];
+
+		memset(&from_ipa_cfg[1], 0, sizeof(from_ipa_cfg[1]));
+		prepare_channel_struct(&from_ipa_channels[1],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST3_CONS,
+			(void *)&from_ipa_cfg[1],
+			sizeof(from_ipa_cfg[1]),
+			en_status);
+		from_ipa_array[1] = &from_ipa_channels[1];
+
+		memset(&from_ipa_cfg[2], 0, sizeof(from_ipa_cfg[2]));
+		prepare_channel_struct(&from_ipa_channels[2],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST4_CONS,
+			(void *)&from_ipa_cfg[2],
+			sizeof(from_ipa_cfg[2]),
+			en_status);
+		from_ipa_array[2] = &from_ipa_channels[2];
+
+		/* To ipa configurations - 1 pipes */
+		memset(&to_ipa_cfg[0], 0, sizeof(to_ipa_cfg[0]));
+		prepare_channel_struct(&to_ipa_channels[0],
+			header.to_ipa_channels_num++,
+			IPA_CLIENT_TEST_PROD,
+			(void *)&to_ipa_cfg[0],
+			sizeof(to_ipa_cfg[0]));
+		to_ipa_array[0] = &to_ipa_channels[0];
+
+		prepare_header_struct(&header, from_ipa_array, to_ipa_array);
+
+		retval = GenericConfigureScenario(&header);
+
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return retval;
+	}
+
+	bool Setup()
+	{
+		bool bRetVal = true;
+
+		if (SetupKernelModule() != true)
+			return bRetVal;
+
+		m_producer.Open(INTERFACE0_TO_IPA_DATA_PATH, INTERFACE0_FROM_IPA_DATA_PATH);
+
+		m_consumer.Open(INTERFACE1_TO_IPA_DATA_PATH, INTERFACE1_FROM_IPA_DATA_PATH);
+		m_consumer2.Open(INTERFACE2_TO_IPA_DATA_PATH, INTERFACE2_FROM_IPA_DATA_PATH);
+		m_defaultConsumer.Open(INTERFACE3_TO_IPA_DATA_PATH, INTERFACE3_FROM_IPA_DATA_PATH);
+
+		if (!m_routing.DeviceNodeIsOpened())
+		{
+			printf("Routing block is not ready for immediate commands!\n");
+			return false;
+		}
+
+		if (!m_filtering.DeviceNodeIsOpened())
+		{
+			printf("Filtering block is not ready for immediate commands!\n");
+			return false;
+		}
+		m_routing.Reset(IPA_IP_v4); // This will issue a Reset command to the Filtering as well
+		m_routing.Reset(IPA_IP_v6); // This will issue a Reset command to the Filtering as well
+		return true;
+	} // Setup()
+
+	bool Teardown()
+	{
+		ipa_ipv6ct_dump_table(m_tableHandle);
+		ipa_ipv6ct_del_tbl(m_tableHandle);
+
+		m_producer.Close();
+		m_consumer.Close();
+		m_consumer2.Close();
+		m_defaultConsumer.Close();
+
+		return true;
+	} // Teardown()
+
+	bool LoadFiles()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		if (!LoadDefaultPacket(IPA_IP_v6, m_extHdrType, m_sendBuffer, m_sendSize))
+		{
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+		printf("Loaded %zu Bytes to Buffer 1\n", m_sendSize);
+
+		if (!LoadDefaultPacket(IPA_IP_v6, m_extHdrType, m_sendBuffer2, m_sendSize2))
+		{
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+		printf("Loaded %zu Bytes to Buffer 2\n", m_sendSize2);
+
+		if (!LoadDefaultPacket(IPA_IP_v6, m_extHdrType, m_sendBuffer3, m_sendSize3))
+		{
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+		printf("Loaded %zu Bytes to Buffer 3\n", m_sendSize3);
+
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}
+
+	// This function creates three IPv6 bypass routing entries and commits them.
+	bool CreateThreeIPv6BypassRoutingTables(const char * bypass0, const char * bypass1, const char * bypass2)
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		struct ipa_ioc_add_rt_rule *rt_rule0 = 0, *rt_rule1 = 0, *rt_rule2 = 0;
+		struct ipa_rt_rule_add *rt_rule_entry;
+
+		rt_rule0 = (struct ipa_ioc_add_rt_rule *)
+			calloc(1,
+				sizeof(struct ipa_ioc_add_rt_rule) +
+				1 * sizeof(struct ipa_rt_rule_add)
+			);
+		if (!rt_rule0) {
+			printf("calloc failed to allocate rt_rule0 in %s\n", __FUNCTION__);
+			return false;
+		}
+		rt_rule1 = (struct ipa_ioc_add_rt_rule *)
+			calloc(1,
+				sizeof(struct ipa_ioc_add_rt_rule) +
+				1 * sizeof(struct ipa_rt_rule_add)
+			);
+		if (!rt_rule1) {
+			printf("calloc failed to allocate rt_rule1 in %s\n", __FUNCTION__);
+			Free(rt_rule0);
+			return false;
+		}
+		rt_rule2 = (struct ipa_ioc_add_rt_rule *)
+			calloc(1,
+				sizeof(struct ipa_ioc_add_rt_rule) +
+				1 * sizeof(struct ipa_rt_rule_add)
+			);
+		if (!rt_rule2) {
+			printf("calloc failed to allocate rt_rule2 in %s\n", __FUNCTION__);
+			Free(rt_rule0);
+			Free(rt_rule1);
+			return false;
+		}
+
+		rt_rule0->num_rules = 1;
+		rt_rule0->ip = IPA_IP_v6;
+		rt_rule0->commit = true;
+		strlcpy(rt_rule0->rt_tbl_name, bypass0, sizeof(rt_rule0->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule0->rules[0];
+		rt_rule_entry->at_rear = false;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0xaabbccdd;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0xeeff0011;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0x22334455;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0x66778899;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;// All Packets will get a "Hit"
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		if (false == m_routing.AddRoutingRule(rt_rule0))
+		{
+			printf("Routing rule addition(rt_rule0) failed!\n");
+			Free(rt_rule2);
+			Free(rt_rule1);
+			Free(rt_rule0);
+			return false;
+		}
+
+
+		rt_rule1->num_rules = 1;
+		rt_rule1->ip = IPA_IP_v6;
+		rt_rule1->commit = true;
+		strlcpy(rt_rule1->rt_tbl_name, bypass1, sizeof(rt_rule1->rt_tbl_name));
+		rt_rule_entry = &rt_rule1->rules[0];
+		rt_rule_entry->at_rear = false;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0xaabbccdd;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0xeeff0011;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0x22334455;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0x66778899;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;// All Packets will get a "Hit"
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		if (false == m_routing.AddRoutingRule(rt_rule1))
+		{
+			printf("Routing rule addition(rt_rule1) failed!\n");
+			Free(rt_rule2);
+			Free(rt_rule1);
+			Free(rt_rule0);
+			return false;
+		}
+
+
+		rt_rule2->num_rules = 1;
+		rt_rule2->ip = IPA_IP_v6;
+		rt_rule2->commit = true;
+		strlcpy(rt_rule2->rt_tbl_name, bypass2, sizeof(rt_rule2->rt_tbl_name));
+		rt_rule_entry = &rt_rule2->rules[0];
+		rt_rule_entry->at_rear = false;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0xaabbccdd;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0xeeff0011;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0x22334455;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0x66778899;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;// All Packets will get a "Hit"
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		if (false == m_routing.AddRoutingRule(rt_rule2))
+		{
+			printf("Routing rule addition(rt_rule2) failed!\n");
+			Free(rt_rule2);
+			Free(rt_rule1);
+			Free(rt_rule0);
+			return false;
+		}
+
+
+		Free(rt_rule2);
+		Free(rt_rule1);
+		Free(rt_rule0);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}
+
+	bool GetThreeIPv6BypassRoutingTables(uint32_t *Hndl0, uint32_t *Hndl1, uint32_t *Hndl2)
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0, routing_table1, routing_table2;
+
+		if (!CreateThreeIPv6BypassRoutingTables(bypass0, bypass1, bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v6;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%pK) Failed.\n", &routing_table0);
+			return false;
+		}
+		routing_table1.ip = IPA_IP_v6;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%pK) Failed.\n", &routing_table1);
+			return false;
+		}
+
+		routing_table2.ip = IPA_IP_v6;
+		strlcpy(routing_table2.name, bypass2, sizeof(routing_table2.name));
+		if (!m_routing.GetRoutingTable(&routing_table2))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table2=0x%pK) Failed.\n", &routing_table2);
+			return false;
+		}
+
+		*Hndl0 = routing_table0.hdl;
+		*Hndl1 = routing_table1.hdl;
+		*Hndl2 = routing_table2.hdl;
+
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}
+
+	bool AddIpv6ctTable()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		const int total_entries = 20;
+
+		int result = ipa_ipv6ct_add_tbl(total_entries, &m_tableHandle);
+		if (result)
+		{
+			printf("Leaving %s, %s(), failed creating IPvC6T table with result %d\n", __FUNCTION__, __FILE__, result);
+			return false;
+		}
+
+		printf("IPv6CT table added, hdl %d\n", m_tableHandle);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}
+
+	bool AddIpv6ctRule(ipa_ipv6ct_rule& rule, uint32_t& rule_hdl) const
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		int result = ipa_ipv6ct_add_rule(m_tableHandle, &rule, &rule_hdl);
+		if (result)
+		{
+			printf("Leaving %s, %s(), failed creating IPvC6T rule with result %d\n", __FUNCTION__, __FILE__, result);
+			return false;
+		}
+		printf("IPv6CT rule added:\ndest lsb %llX, dest msb %llX, dest port %d\ndir %d, proto %d\nsrc lsb 0x%llX, src msb 0x%llX, src port %d\n",
+			(long long unsigned int)rule.dest_ipv6_lsb, (long long unsigned int)rule.dest_ipv6_msb,
+			rule.dest_port, rule.direction_settings,
+			rule.protocol, (long long unsigned int)rule.src_ipv6_lsb, (long long unsigned int)rule.src_ipv6_msb,
+			rule.src_port);
+
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}
+
+	void InitIpv6ctRule(ipa_ipv6ct_rule& rule, uint64_t change_bit) const
+	{
+		rule.dest_ipv6_lsb = m_outbound_dst_addr_lsb ^ change_bit;
+		rule.dest_ipv6_msb = m_outbound_dst_addr_msb;
+		rule.dest_port = m_outbound_dst_port;
+		rule.direction_settings = m_direction_settings;
+		rule.protocol = IPPROTO_TCP;
+		rule.src_ipv6_lsb = m_outbound_src_addr_lsb ^ change_bit;
+		rule.src_ipv6_msb = m_outbound_src_addr_msb;
+		rule.src_port = m_outbound_src_port;
+	}
+
+	virtual bool AddIpv6ctRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		ipa_ipv6ct_rule rule;
+		InitIpv6ctRule(rule, 0);
+
+		uint32_t rule_hdl;
+		bool result = AddIpv6ctRule(rule, rule_hdl);
+
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+
+	virtual bool ModifyPackets() = 0;
+	virtual bool AddRoutingFilteringRules() = 0;
+	virtual bool ReceivePacketsAndCompare() = 0;
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		res = AddRoutingFilteringRules();
+		if (false == res) {
+			printf("Failed adding routing and filtering rules.\n");
+			return false;
+		}
+
+		res = AddIpv6ctTable();
+		if (false == res)
+		{
+			printf("Failed adding IPv6 connection tracking table.\n");
+			return false;
+		}
+
+		res = AddIpv6ctRules();
+		if (false == res)
+		{
+			printf("Failed adding IPv6 connection tracking rules.\n");
+			return false;
+		}
+
+		res = LoadFiles();
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		res = ModifyPackets();
+		if (false == res) {
+			printf("Failed to modify packets.\n");
+			return false;
+		}
+
+		// Send first packet
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		printf("Leaving %s, %s(), Returning %d\n", __FUNCTION__, __FILE__, isSuccess);
+
+		return isSuccess;
+	} // Run()
+
+	void ModifyPackets(uint64_t dstAddrLsb, uint64_t dstAddrMsb, uint16_t dstPort,
+		uint64_t srcAddrLsb, uint64_t srcAddrMsb, uint16_t srcPort)
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		// destination
+		uint64_t address = HostToNetwork(dstAddrLsb);
+		memcpy(&m_sendBuffer[IPV6_DST_ADDRESS_LSB_OFFSET], &address, sizeof(address));
+
+		address = HostToNetwork(dstAddrMsb);
+		memcpy(&m_sendBuffer[IPV6_DST_ADDRESS_MSB_OFFSET], &address, sizeof(address));
+
+		uint16_t port = ntohs(dstPort);
+		memcpy(&m_sendBuffer[IPV6_DST_PORT_OFFSET], &port, sizeof(port));
+
+		// source
+		address = HostToNetwork(srcAddrLsb);
+		memcpy(&m_sendBuffer[IPV6_SRC_ADDRESS_LSB_OFFSET], &address, sizeof(address));
+
+		address = HostToNetwork(srcAddrMsb);
+		memcpy(&m_sendBuffer[IPV6_SRC_ADDRESS_MSB_OFFSET], &address, sizeof(address));
+
+		port = ntohs(srcPort);
+		memcpy(&m_sendBuffer[IPV6_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+	}// ModifyPacktes ()
+
+	virtual bool AddRoutingFilteringRules(enum ipa_flt_action flt_action, uint64_t dst_addr_msb, uint64_t dst_addr_lsb)
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+
+		if (!CreateThreeIPv6BypassRoutingTables(bypass0, bypass1, bypass2))
+		{
+			printf("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+		printf("CreateThreeBypassRoutingTables completed successfully\n");
+
+		ipa_ioc_get_rt_tbl routing_table0;
+		routing_table0.ip = IPA_IP_v6;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table0=0x%pK) Failed.\n", &routing_table0);
+			return false;
+		}
+
+		ipa_ioc_get_rt_tbl routing_table1;
+		routing_table1.ip = IPA_IP_v6;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			printf("m_routing.GetRoutingTable(&routing_table1=0x%pK) Failed.\n", &routing_table1);
+			return false;
+		}
+
+		IPAFilteringTable FilterTable0;
+		ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v6, IPA_CLIENT_TEST_PROD, false, 1);
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1, flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = flt_action;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;// Exact Match
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = GetHigh32(dst_addr_msb); // Filter DST_IP
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = GetLow32(dst_addr_msb);
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = GetHigh32(dst_addr_lsb);
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = GetLow32(dst_addr_lsb);
+
+		printf("flt_rule_entry was set successfully, preparing for insertion....\n");
+
+		if (((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable()))
+		{
+			printf("%s::Error Adding Rule to Filter Table, aborting...\n", __FUNCTION__);
+			return false;
+		}
+		else
+		{
+			printf("flt rule hdl0=0x%x, status=0x%x\n",
+				FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ReceivePacketsAndCompare(bool packetPassExpected)
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		// Receive results
+		Byte rxBuff1[0x400];
+		size_t receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		bool isSuccess = true;
+		if (packetPassExpected)
+		{
+			// Compare results
+			if (!CompareResultVsGolden(m_sendBuffer, m_sendSize, rxBuff1, receivedSize))
+			{
+				printf("Comparison of Buffer0 Failed!\n");
+				isSuccess = false;
+			}
+		}
+		else
+		{
+			if (receivedSize)
+			{
+				isSuccess = false;
+				printf("got data while expected packet to be blocked, failing\n");
+			}
+		}
+
+		char recievedBuffer[256] = {0};
+		char SentBuffer[256] = {0};
+		size_t j;
+
+		for (j = 0; j < m_sendSize; j++)
+		{
+			snprintf(&SentBuffer[3 * j], sizeof(SentBuffer)-(3 * j + 1), " %02X", m_sendBuffer[j]);
+		}
+
+		for (j = 0; j < receivedSize; j++)
+		{
+			snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer)-(3 * j + 1), " %02X", rxBuff1[j]);
+		}
+		printf("Expected Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n",
+			m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return isSuccess;
+	}
+
+protected:
+
+	static Filtering m_filtering;
+	static RoutingDriverWrapper m_routing;
+	InterfaceAbstraction m_producer;
+	InterfaceAbstraction m_consumer;
+	InterfaceAbstraction m_consumer2;
+	InterfaceAbstraction m_defaultConsumer;
+
+	static const size_t BUFF_MAX_SIZE = 1024;
+
+	Byte m_sendBuffer[BUFF_MAX_SIZE];	// First input file / IP packet
+	Byte m_sendBuffer2[BUFF_MAX_SIZE];	// Second input file / IP packet
+	Byte m_sendBuffer3[BUFF_MAX_SIZE];	// Third input file (default) / IP packet
+	size_t m_sendSize;
+	size_t m_sendSize2;
+	size_t m_sendSize3;
+	static const ipv6_ext_hdr_type m_extHdrType = NONE;
+
+	uint64_t m_outbound_dst_addr_msb;
+	uint64_t m_outbound_dst_addr_lsb;
+	uint16_t m_outbound_dst_port;
+	uint64_t m_outbound_src_addr_msb;
+	uint64_t m_outbound_src_addr_lsb;
+	uint16_t m_outbound_src_port;
+	ipa_ipv6_ct_direction_settings_type m_direction_settings;
+
+	uint32_t m_tableHandle;
+};
+
+RoutingDriverWrapper IpaIPv6CTBlockTestFixture::m_routing;
+Filtering IpaIPv6CTBlockTestFixture::m_filtering;
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test001: IPv6CT send outbound packet  */
+/*---------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest001 : public IpaIPv6CTBlockTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest001()
+	{
+		m_name = "IpaIPV6CTBlockTest001";
+		m_description =
+			"IPv6CT block test 001 - IPv6CT passes successfully one packet in outbound direction\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one outbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add IPv6CT rule for the packet\n";
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_SRC_NAT,
+			m_outbound_dst_addr_msb, m_outbound_dst_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port,
+			m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(true);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test002: IPv6CT send inbound packet  */
+/*---------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest002 : public IpaIPv6CTBlockTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest002()
+	{
+		m_name = "IpaIPV6CTBlockTest002";
+		m_description =
+			"IPv6CT block test 002 - IPv6CT passes successfully one packet in inbound direction\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one inbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add IPv6CT rule for the packet\n";
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_DST_NAT,
+			m_outbound_src_addr_msb, m_outbound_src_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port,
+			m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(true);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test003: IPv6CT send outbound packet - without IPV6CT rule */
+/*---------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest003 : public IpaIPv6CTBlockTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest003()
+	{
+		m_name = "IpaIPV6CTBlockTest003";
+		m_description =
+			"IPv6CT block test 003 - IPv6CT blocks one packet in outbound direction due to rule absence\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one outbound filtering rule: Destination IP Exactly Match.\n";
+		Register(*this);
+	}
+
+	virtual bool AddIpv6ctRules()
+	{
+		printf("not adding IPv6CT rule for packet - blocking expected %s %s\n", __FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_SRC_NAT,
+			m_outbound_dst_addr_msb, m_outbound_dst_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port,
+			m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(false);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test004: IPv6CT send inbound packet - without IPV6CT rule */
+/*---------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest004 : public IpaIPv6CTBlockTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest004()
+	{
+		m_name = "IpaIPV6CTBlockTest004";
+		m_description =
+			"IPv6CT block test 004 - IPv6CT blocks one packet in inbound direction due to rule absence\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one inbound filtering rule: Destination IP Exactly Match.\n";
+		Register(*this);
+	}
+
+	virtual bool AddIpv6ctRules()
+	{
+		printf("not adding IPv6CT rule for packet - blocking expected %s %s\n", __FUNCTION__, __FILE__);
+		return true;
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_DST_NAT,
+			m_outbound_src_addr_msb, m_outbound_src_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port,
+			m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(false);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test005: IPv6CT send outbound packet with inbound filtering rule */
+/*---------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest005 : public IpaIPv6CTBlockTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest005()
+	{
+		m_name = "IpaIPV6CTBlockTest005";
+		m_description =
+			"IPv6CT block test 005 - IPv6CT blocks one packet in outbound direction, because the filtering rule\n"
+			"                        action is inbound\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one inbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add IPv6CT rule for the packet\n";
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_DST_NAT,
+			m_outbound_dst_addr_msb, m_outbound_dst_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port,
+			m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(false);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test006: IPv6CT send inbound packet with outbound filtering rule */
+/*---------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest006 : public IpaIPv6CTBlockTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest006()
+	{
+		m_name = "IpaIPV6CTBlockTest006";
+		m_description =
+			"IPv6CT block test 006 - IPv6CT blocks one packet in inbound direction, because the filtering rule\n"
+			"                        action is outbound\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one outbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add IPv6CT rule for the packet\n";
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_SRC_NAT,
+			m_outbound_src_addr_msb, m_outbound_src_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port,
+			m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(false);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test007: IPv6CT block outbound packet while disabled outbound direction                     */
+/*---------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest007 : public IpaIPv6CTBlockTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest007()
+	{
+		m_name = "IpaIPV6CTBlockTest007";
+		m_description =
+			"IPv6CT block test 007 - IPv6CT blocks one packet in outbound direction, because the outbound direction\n"
+			"                        is disabled\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one outbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add IPv6CT rule for the packet with disabled outbound direction\n";
+		m_direction_settings = IPA_IPV6CT_DIRECTION_ALLOW_IN;
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_SRC_NAT,
+			m_outbound_dst_addr_msb, m_outbound_dst_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port,
+			m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(false);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test008: IPv6CT block inbound packet with disabled inbound direction                        */
+/*---------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest008 : public IpaIPv6CTBlockTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest008()
+	{
+		m_name = "IpaIPV6CTBlockTest008";
+		m_description =
+			"IPv6CT block test 008 - IPv6CT blocks one packet in inbound direction, because the inbound direction\n"
+			"                        is disabled\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one inbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add IPv6CT rule for the packet with disabled inbound direction\n";
+		m_direction_settings = IPA_IPV6CT_DIRECTION_ALLOW_OUT;
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_DST_NAT,
+			m_outbound_src_addr_msb, m_outbound_src_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port,
+			m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(false);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+class IpaIPv6CTBlockExpansionTableTestFixture : public IpaIPv6CTBlockTestFixture
+{
+public:
+
+	virtual bool AddIpv6ctRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		ipa_ipv6ct_rule rule;
+		InitIpv6ctRule(rule, 8);
+
+		uint32_t rule_hdl;
+		if (!AddIpv6ctRule(rule, rule_hdl))
+		{
+			return false;
+		}
+
+		bool result = IpaIPv6CTBlockTestFixture::AddIpv6ctRules();
+
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test009: IPv6CT send outbound packet with rule in expansion table */
+/*---------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest009 : public IpaIPv6CTBlockExpansionTableTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest009()
+	{
+		m_name = "IpaIPV6CTBlockTest009";
+		m_description =
+			"IPv6CT block test 009 - IPv6CT passes successfully one packet in outbound direction with rule in\n"
+			"                        expansion table\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one outbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add an IPv6CT rule to occupy base table. This rule is not supposed to match a packet\n"
+			"4. Add IPv6CT rule for the packet to the expansion table\n";
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_SRC_NAT,
+			m_outbound_dst_addr_msb, m_outbound_dst_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port,
+			m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(true);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test010: IPv6CT send inbound packet with rule in expansion table */
+/*---------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest010 : public IpaIPv6CTBlockExpansionTableTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest010()
+	{
+		m_name = "IpaIPV6CTBlockTest010";
+		m_description =
+			"IPv6CT block test 010 - IPv6CT passes successfully one packet in inbound direction with rule in\n"
+			"                        expansion table\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one inbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add an IPv6CT rule to occupy base table. This rule is not supposed to match a packet\n"
+			"4. Add IPv6CT rule for the packet to the expansion table\n";
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_DST_NAT,
+			m_outbound_src_addr_msb, m_outbound_src_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port,
+			m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(true);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+class IpaIPv6CTBlockRuleDeleteTestFixture : public IpaIPv6CTBlockTestFixture
+{
+public:
+
+	virtual bool AddIpv6ctRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		ipa_ipv6ct_rule rule;
+		InitIpv6ctRule(rule, 0);
+
+		uint32_t rule_hdl;
+		if (!AddIpv6ctRule(rule, rule_hdl))
+		{
+			return false;
+		}
+
+		int result = ipa_ipv6ct_del_rule(m_tableHandle, rule_hdl);
+		if (result)
+		{
+			printf("Leaving %s, %s(), failed delete IPvC6T rule %d with result %d\n", __FUNCTION__, __FILE__,
+				rule_hdl, result);
+			return false;
+		}
+
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test011: IPv6CT block outbound packet while the rule was deleted                            */
+/*---------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest011 : public IpaIPv6CTBlockRuleDeleteTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest011()
+	{
+		m_name = "IpaIPV6CTBlockTest011";
+		m_description =
+			"IPv6CT block test 011 - IPv6CT blocks one packet in outbound direction due to the rule deletion\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one outbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add IPv6CT rule for the packet\n"
+			"4. Delete IPv6CT rule for the packet\n";
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_SRC_NAT,
+			m_outbound_dst_addr_msb, m_outbound_dst_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port,
+			m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(false);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test012: IPv6CT block inbound packet while the rule was deleted                             */
+/*---------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest012 : public IpaIPv6CTBlockRuleDeleteTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest012()
+	{
+		m_name = "IpaIPV6CTBlockTest012";
+		m_description =
+			"IPv6CT block test 012 - IPv6CT blocks one packet in inbound direction due to the rule deletion\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one inbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add IPv6CT rule for the packet\n"
+			"4. Delete IPv6CT rule for the packet\n";
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_DST_NAT,
+			m_outbound_src_addr_msb, m_outbound_src_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port,
+			m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(false);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+class IpaIPv6CTBlockRuleDeleteExpansionTableTestFixture : public IpaIPv6CTBlockRuleDeleteTestFixture
+{
+public:
+
+	virtual bool AddIpv6ctRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		ipa_ipv6ct_rule rule;
+		InitIpv6ctRule(rule, 8);
+
+		uint32_t rule_hdl;
+		if (!AddIpv6ctRule(rule, rule_hdl))
+		{
+			return false;
+		}
+
+		bool result = IpaIPv6CTBlockRuleDeleteTestFixture::AddIpv6ctRules();
+
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test013: IPv6CT block outbound packet while the rule in expansion table was deleted         */
+/*---------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest013 : public IpaIPv6CTBlockRuleDeleteExpansionTableTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest013()
+	{
+		m_name = "IpaIPV6CTBlockTest013";
+		m_description =
+			"IPv6CT block test 013 - IPv6CT blocks one packet in outbound direction due to the rule deletion from\n"
+			"                        the expansion table\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one outbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add an IPv6CT rule to occupy base table. This rule is not supposed to match a packet\n"
+			"4. Add IPv6CT rule for the packet to the expansion table\n"
+			"5. Delete IPv6CT rule for the packet from the expansion table\n";
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_SRC_NAT,
+			m_outbound_dst_addr_msb, m_outbound_dst_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port,
+			m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(false);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------*/
+/* Test014: IPv6CT block inbound packet while the rule in expansion table was deleted          */
+/*---------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest014 : public IpaIPv6CTBlockRuleDeleteExpansionTableTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest014()
+	{
+		m_name = "IpaIPV6CTBlockTest014";
+		m_description =
+			"IPv6CT block test 014 - IPv6CT blocks one packet in inbound direction due to the rule deletion from\n"
+			"                        the expansion table\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one inbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add an IPv6CT rule to occupy base table. This rule is not supposed to match a packet\n"
+			"4. Add IPv6CT rule for the packet to the expansion table\n"
+			"5. Delete IPv6CT rule for the packet from the expansion table\n";
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_DST_NAT,
+			m_outbound_src_addr_msb, m_outbound_src_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port,
+			m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(false);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+class IpaIPv6CTBlockHeadRuleDeleteTestFixture : public IpaIPv6CTBlockTestFixture
+{
+public:
+
+	virtual bool AddIpv6ctRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		ipa_ipv6ct_rule rule;
+		InitIpv6ctRule(rule, 8);
+
+		uint32_t rule_hdl;
+		if (!AddIpv6ctRule(rule, rule_hdl))
+		{
+			return false;
+		}
+
+		if (!IpaIPv6CTBlockTestFixture::AddIpv6ctRules())
+		{
+			return false;
+		}
+
+		int result = ipa_ipv6ct_del_rule(m_tableHandle, rule_hdl);
+		if (result)
+		{
+			printf("Leaving %s, %s(), failed delete IPvC6T rule %d with result %d\n", __FUNCTION__, __FILE__,
+				rule_hdl, result);
+			return false;
+		}
+
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------------------------*/
+/* Test015: IPv6CT send outbound packet with rule in expansion table while the rule in the list head was deleted */
+/*---------------------------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest015 : public IpaIPv6CTBlockHeadRuleDeleteTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest015()
+	{
+		m_name = "IpaIPV6CTBlockTest015";
+		m_description =
+			"IPv6CT block test 015 - IPv6CT passes successfully one packet in outbound direction with rule in\n"
+			"                        expansion table, while the list head was deleted\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one outbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add an IPv6CT rule to occupy base table. This rule is not supposed to match a packet\n"
+			"4. Add IPv6CT rule for the packet to the expansion table\n"
+			"5. Delete IPv6CT rule in the list head\n";
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_SRC_NAT,
+			m_outbound_dst_addr_msb, m_outbound_dst_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port,
+			m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(true);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*---------------------------------------------------------------------------------------------------------------*/
+/* Test016: IPv6CT send inbound packet with rule in expansion table while the rule in the list head was deleted  */
+/*---------------------------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest016 : public IpaIPv6CTBlockHeadRuleDeleteTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest016()
+	{
+		m_name = "IpaIPV6CTBlockTest016";
+		m_description =
+			"IPv6CT block test 016 - IPv6CT passes successfully one packet in inbound direction with rule in\n"
+			"                        expansion table, while the list head was deleted\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one inbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add an IPv6CT rule to occupy base table. This rule is not supposed to match a packet\n"
+			"4. Add IPv6CT rule for the packet to the expansion table\n"
+			"5. Delete IPv6CT rule in the list head\n";
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_DST_NAT,
+			m_outbound_src_addr_msb, m_outbound_src_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port,
+			m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(true);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+class IpaIPv6CTBlockMiddleRuleDeleteTestFixture : public IpaIPv6CTBlockHeadRuleDeleteTestFixture
+{
+public:
+
+	virtual bool AddIpv6ctRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		ipa_ipv6ct_rule rule;
+		InitIpv6ctRule(rule, 1);
+
+		uint32_t rule_hdl;
+		if (!AddIpv6ctRule(rule, rule_hdl))
+		{
+			return false;
+		}
+
+		bool result = IpaIPv6CTBlockHeadRuleDeleteTestFixture::AddIpv6ctRules();
+
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*------------------------------------------------------------------------------------------------------------*/
+/* Test017: IPv6CT send outbound packet with rule in expansion table while the rule in the middle of the list */
+/*          was deleted                                                                                       */
+/*------------------------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest017 : public IpaIPv6CTBlockMiddleRuleDeleteTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest017()
+	{
+		m_name = "IpaIPV6CTBlockTest017";
+		m_description =
+			"IPv6CT block test 017 - IPv6CT passes successfully one packet in outbound direction with rule in\n"
+			"                        expansion table, while the rule in the middle of the list was deleted\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one outbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add two IPv6CT rules: one to base table and other to expansion table. These rules are not supposed\n"
+			"   to match a packet\n"
+			"4. Add IPv6CT rule for the packet to the expansion table\n"
+			"5. Delete IPv6CT rule in the middle of the list\n";
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_SRC_NAT,
+			m_outbound_dst_addr_msb, m_outbound_dst_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port,
+			m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(true);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+/*------------------------------------------------------------------------------------------------------------*/
+/* Test018: IPv6CT send inbound packet with rule in expansion table while the rule in the middle of the list  */
+/*          was deleted                                                                                       */
+/*------------------------------------------------------------------------------------------------------------*/
+class IpaIPV6CTBlockTest018 : public IpaIPv6CTBlockMiddleRuleDeleteTestFixture
+{
+public:
+
+	IpaIPV6CTBlockTest018()
+	{
+		m_name = "IpaIPV6CTBlockTest018";
+		m_description =
+			"IPv6CT block test 018 - IPv6CT passes successfully one packet in inbound direction with rule in\n"
+			"                        expansion table, while the rule in the middle of the list was deleted\n"
+			"1. Generate and commit three routing tables.\n"
+			"   Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1 and 2 (accordingly))\n"
+			"2. Generate and commit one inbound filtering rule: Destination IP Exactly Match.\n"
+			"3. Add two IPv6CT rules to occupy base table and the middle of the list. These rules are not supposed\n"
+			"   to match a packet\n"
+			"4. Add IPv6CT rule for the packet to the expansion table\n"
+			"5. Delete IPv6CT rule in the middle of the list\n";
+		Register(*this);
+	}
+
+	virtual bool AddRoutingFilteringRules()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::AddRoutingFilteringRules(IPA_PASS_TO_DST_NAT,
+			m_outbound_src_addr_msb, m_outbound_src_addr_lsb);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}// AddRoutingFilteringRules()
+
+	virtual bool ModifyPackets()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		IpaIPv6CTBlockTestFixture::ModifyPackets(m_outbound_src_addr_lsb, m_outbound_src_addr_msb, m_outbound_src_port,
+			m_outbound_dst_addr_lsb, m_outbound_dst_addr_msb, m_outbound_dst_port);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return true;
+	}// ModifyPackets()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+		bool result = IpaIPv6CTBlockTestFixture::ReceivePacketsAndCompare(true);
+		printf("Leaving %s, %s()\n", __FUNCTION__, __FILE__);
+		return result;
+	}
+};
+
+// IPv6CT outbound packet test
+static class IpaIPV6CTBlockTest001 IpaIPV6CTBlockTest001;
+
+// IPv6CT inbound packet test
+static class IpaIPV6CTBlockTest002 IpaIPV6CTBlockTest002;
+
+// IPv6CT block outbound packet test
+static class IpaIPV6CTBlockTest003 IpaIPV6CTBlockTest003;
+
+// IPv6CT block inbound packet test
+static class IpaIPV6CTBlockTest004 IpaIPV6CTBlockTest004;
+
+// IPv6CT block outbound packet on inbound filtering rule test
+static class IpaIPV6CTBlockTest005 IpaIPV6CTBlockTest005;
+
+// IPv6CT block inbound packet on outbound filtering rule test
+static class IpaIPV6CTBlockTest006 IpaIPV6CTBlockTest006;
+
+// IPv6CT block outbound packet while disabled outbound direction
+static class IpaIPV6CTBlockTest007 IpaIPV6CTBlockTest007;
+
+// IPv6CT block inbound packet with disabled inbound direction
+static class IpaIPV6CTBlockTest008 IpaIPV6CTBlockTest008;
+
+// IPv6CT send outbound packet with rule in expansion table
+static class IpaIPV6CTBlockTest009 IpaIPV6CTBlockTest009;
+
+// IPv6CT send inbound packet with rule in expansion table
+static class IpaIPV6CTBlockTest010 IpaIPV6CTBlockTest010;
+
+// IPv6CT block outbound packet while the rule was deleted
+static class IpaIPV6CTBlockTest011 IpaIPV6CTBlockTest011;
+
+// IPv6CT block inbound packet while the rule was deleted
+static class IpaIPV6CTBlockTest012 IpaIPV6CTBlockTest012;
+
+// IPv6CT block outbound packet while the rule in expansion table was deleted
+static class IpaIPV6CTBlockTest013 IpaIPV6CTBlockTest013;
+
+// IPv6CT block inbound packet while the rule in expansion table was deleted
+static class IpaIPV6CTBlockTest014 IpaIPV6CTBlockTest014;
+
+// IPv6CT send outbound packet with rule in expansion table while the rule in list head was deleted
+static class IpaIPV6CTBlockTest015 IpaIPV6CTBlockTest015;
+
+// IPv6CT send inbound packet with rule in expansion table while the rule in list head was deleted
+static class IpaIPV6CTBlockTest016 IpaIPV6CTBlockTest016;
+
+// IPv6CT send outbound packet with rule in expansion table while the rule in the middle of the list was deleted
+static class IpaIPV6CTBlockTest017 IpaIPV6CTBlockTest017;
+
+// IPv6CT send inbound packet with rule in expansion table while the rule in the middle of the list was deleted
+static class IpaIPV6CTBlockTest018 IpaIPV6CTBlockTest018;
+

+ 155 - 0
kernel-tests/InterfaceAbstraction.cpp

@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "InterfaceAbstraction.h"
+
+#define MAX_OPEN_RETRY 10000
+
+bool InterfaceAbstraction::Open(const char * toIPAPath, const char * fromIPAPath)
+{
+	int tries_cnt = MAX_OPEN_RETRY;
+	if (NULL == toIPAPath && NULL == fromIPAPath)
+	{
+		printf("InterfaceAbstraction constructor got 2 null arguments.\n");
+		exit(0);
+	}
+
+	if (NULL != toIPAPath) {
+		while (tries_cnt > 0) {
+			printf("trying to open %s %d/%d\n", toIPAPath, MAX_OPEN_RETRY - tries_cnt, MAX_OPEN_RETRY);
+			// Sleep for 5 msec
+			usleep(5000);
+			m_toIPADescriptor = open(toIPAPath, O_WRONLY);
+			if (-1 != m_toIPADescriptor) {
+				printf("Success!\n");
+				break;
+			}
+			tries_cnt--;
+		}
+		printf("open retries_cnt=%d\n", MAX_OPEN_RETRY - tries_cnt);
+		if (-1 == m_toIPADescriptor) {
+			printf("InterfaceAbstraction failed while opening %s.\n", toIPAPath);
+			exit(0);
+		}
+		m_toChannelName = toIPAPath;
+		printf("%s device node opened, fd = %d.\n", toIPAPath, m_toIPADescriptor);
+	}
+	tries_cnt = MAX_OPEN_RETRY;
+	if (NULL != fromIPAPath) {
+		while (tries_cnt > 0) {
+			printf("trying to open %s %d/%d\n", fromIPAPath, MAX_OPEN_RETRY - tries_cnt, MAX_OPEN_RETRY);
+			// Sleep for 5 msec
+			usleep(5000);
+			m_fromIPADescriptor = open(fromIPAPath, O_RDONLY);
+			if (-1 != m_fromIPADescriptor) {
+				printf("Success!\n");
+				break;
+			}
+			tries_cnt--;
+		}
+		printf("open retries_cnt=%d\n", MAX_OPEN_RETRY - tries_cnt);
+		if (-1 == m_fromIPADescriptor)
+		{
+			printf("InterfaceAbstraction failed on opening %s.\n", fromIPAPath);
+			exit(0);
+		}
+		m_fromChannelName = fromIPAPath;
+		printf("%s device node opened, fd = %d.\n", fromIPAPath, m_fromIPADescriptor);
+	}
+
+	return true;
+}/*Ctor*/
+
+void InterfaceAbstraction::Close()
+{
+	close(m_toIPADescriptor);
+	close(m_fromIPADescriptor);
+}
+
+bool InterfaceAbstraction::SendData(unsigned char *buf, size_t size)
+{
+	int bytesWritten = 0;
+
+	printf("Trying to write %zu bytes to %d.\n", size, m_toIPADescriptor);
+
+	bytesWritten = write(m_toIPADescriptor, buf, size);
+	if (-1 == bytesWritten)
+	{
+		int err = errno;
+		printf(
+		"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
+		printf(
+		"Failed to execute command\n write(m_toIPADescriptor, buf, size);\n "
+		"m_toIPADescriptor=%d, buf=0x%p, size=%zu",m_toIPADescriptor,
+		buf,
+		size);
+		printf("Error on write execution, errno=%d, Quitting!\n", err);
+		printf(
+		"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
+		exit(-1);
+	}
+
+	printf("bytesWritten = %d.\n", bytesWritten);
+
+	return bytesWritten;
+}
+
+int InterfaceAbstraction::ReceiveData(unsigned char *buf, size_t size)
+{
+	size_t bytesRead = 0;
+	size_t totalBytesRead = 0;
+	bool continueRead = false;
+
+	do
+	{
+		printf("Trying to read %zu bytes from %d.\n", size, m_fromIPADescriptor);
+
+		bytesRead = read(m_fromIPADescriptor, (void*)buf, size);
+		printf("Read %zu bytes.\n", bytesRead);
+		totalBytesRead += bytesRead;
+		if (bytesRead == size)
+			continueRead = true;
+		else
+			continueRead = false;
+	} while (continueRead);
+
+	return totalBytesRead;
+}
+
+InterfaceAbstraction::~InterfaceAbstraction()
+{
+	close(m_fromIPADescriptor);
+	m_fromChannelName = "";
+
+	close(m_toIPADescriptor);
+	m_toChannelName = "";
+}

+ 59 - 0
kernel-tests/InterfaceAbstraction.h

@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef INTERFACE_ABSTRACTION_H_
+#define INTERFACE_ABSTRACTION_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+
+typedef unsigned char Byte;
+
+using namespace std;
+
+class InterfaceAbstraction
+{
+
+public:
+	~InterfaceAbstraction();
+	bool Open(const char *toIPAPath, const char *fromIPAPath);
+	void Close();
+	bool SendData(unsigned char *buffer, size_t size);
+	int ReceiveData(unsigned char *buf, size_t size);
+
+	string m_toChannelName;
+	string m_fromChannelName;
+
+private:
+	int m_toIPADescriptor;
+	int m_fromIPADescriptor;
+};
+
+#endif

+ 59 - 0
kernel-tests/Logger.cpp

@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "Logger.h"
+
+////////////////////////////////////////////////////////////////////////////
+
+//The trace level of the system will be used to choose the system printing level
+Logger::Logger(TraceLevel nTraceLevel)
+{
+	m_nTraceLevelToPresent = nTraceLevel;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+//This method will be use to print messages. it will also gie a trace level for each message.
+void Logger::AddMessage(TraceLevel nTraceLevel, const char *format, ...)
+{
+
+	//in case the trace level is not "high" no print should be made.
+	if (nTraceLevel < m_nTraceLevelToPresent)
+	{
+		return;
+	}
+
+	va_list ap;
+	va_start(ap, format);
+	vprintf(format, ap);
+	va_end(ap);
+}
+
+////////////////////////////////////////////////////////////////////////////
+

+ 60 - 0
kernel-tests/Logger.h

@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LOGGER_H_
+#define LOGGER_H_
+
+#include <stdio.h>
+#include <stdarg.h>
+
+using namespace std;
+
+typedef enum{
+	LOG_DEVELOPMENT = 0,
+	LOG_ERROR       = 0,
+	LOG_VERBOSE     = 1
+} TraceLevel;
+
+/*This class will controll all the printing in the test application
+ *In each test there will be many printing while each
+ *specific print will define it's "importancy"(TraceLevel)
+ *During the development of the test it is
+ *strongly suggested to use LOG_DEVELOPMENT.
+ */
+
+class Logger
+{
+public:
+	Logger(TraceLevel nTraceLevelToPresent);
+	void AddMessage(TraceLevel nTraceLevel, const char *format, ...);
+private:
+	int m_nTraceLevelToPresent;
+};
+
+#endif /* LOGGER_H_ */

+ 1169 - 0
kernel-tests/MBIMAggregationTestFixtureConf11.cpp

@@ -0,0 +1,1169 @@
+/*
+ * Copyright (c) 2017-2018,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "MBIMAggregationTestFixtureConf11.h"
+#include "TestManager.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+
+//define the static Pipes which will be used by all derived tests.
+Pipe MBIMAggregationTestFixtureConf11::m_IpaToUsbPipeAgg(IPA_CLIENT_TEST2_CONS,
+		IPA_TEST_CONFIGURATION_11);
+Pipe MBIMAggregationTestFixtureConf11::m_UsbToIpaPipe(IPA_CLIENT_TEST_PROD,
+		IPA_TEST_CONFIGURATION_11);
+Pipe MBIMAggregationTestFixtureConf11::m_IpaToUsbPipe(IPA_CLIENT_TEST3_CONS,
+		IPA_TEST_CONFIGURATION_11);
+Pipe MBIMAggregationTestFixtureConf11::m_UsbToIpaPipeDeagg(IPA_CLIENT_TEST2_PROD,
+		IPA_TEST_CONFIGURATION_11);
+Pipe MBIMAggregationTestFixtureConf11::m_IpaToUsbPipeAggTime(IPA_CLIENT_TEST_CONS,
+		IPA_TEST_CONFIGURATION_11);
+Pipe MBIMAggregationTestFixtureConf11::m_IpaToUsbPipeAgg0Limits(IPA_CLIENT_TEST4_CONS,
+		IPA_TEST_CONFIGURATION_11);
+
+RoutingDriverWrapper MBIMAggregationTestFixtureConf11::m_Routing;
+Filtering MBIMAggregationTestFixtureConf11::m_Filtering;
+HeaderInsertion MBIMAggregationTestFixtureConf11::m_HeaderInsertion;
+
+/////////////////////////////////////////////////////////////////////////////////
+
+MBIMAggregationTestFixtureConf11::MBIMAggregationTestFixtureConf11(bool generic_agg)
+: mGenericAgg(generic_agg)
+{
+	if (mGenericAgg) {
+		m_testSuiteName.push_back("GenMbimAgg");
+		m_minIPAHwType = IPA_HW_v4_0;
+	} else {
+		m_testSuiteName.push_back("Mbim16Agg");
+		m_maxIPAHwType = IPA_HW_v3_5_1;
+	}
+	Register(*this);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+int MBIMAggregationTestFixtureConf11::SetupKernelModule()
+{
+	int retval;
+	struct ipa_channel_config from_ipa_channels[4];
+	struct test_ipa_ep_cfg from_ipa_cfg[4];
+	struct ipa_channel_config to_ipa_channels[2];
+	struct test_ipa_ep_cfg to_ipa_cfg[2];
+
+	struct ipa_test_config_header header = {0};
+	struct ipa_channel_config *to_ipa_array[2];
+	struct ipa_channel_config *from_ipa_array[4];
+
+	/* From ipa configurations - 4 pipes */
+	memset(&from_ipa_cfg[0], 0, sizeof(from_ipa_cfg[0]));
+	from_ipa_cfg[0].aggr.aggr_en = IPA_ENABLE_AGGR;
+	from_ipa_cfg[0].aggr.aggr = IPA_MBIM_16;
+	from_ipa_cfg[0].aggr.aggr_byte_limit = 1;
+	from_ipa_cfg[0].aggr.aggr_time_limit = 0;
+	if (mGenericAgg) {
+		from_ipa_cfg[0].hdr.hdr_len = 4;
+		from_ipa_cfg[0].hdr_ext.hdr_pad_to_alignment = 2;
+	} else {
+		from_ipa_cfg[0].hdr.hdr_len = 1;
+	}
+
+	prepare_channel_struct(&from_ipa_channels[0],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST2_CONS,
+			(void *)&from_ipa_cfg[0],
+			sizeof(from_ipa_cfg[0]),
+			false);
+	from_ipa_array[0] = &from_ipa_channels[0];
+
+	memset(&from_ipa_cfg[1], 0, sizeof(from_ipa_cfg[1]));
+	prepare_channel_struct(&from_ipa_channels[1],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST3_CONS,
+			(void *)&from_ipa_cfg[1],
+			sizeof(from_ipa_cfg[1]),
+			false);
+	from_ipa_array[1] = &from_ipa_channels[1];
+
+	memset(&from_ipa_cfg[2], 0, sizeof(from_ipa_cfg[2]));
+	from_ipa_cfg[2].aggr.aggr_en = IPA_ENABLE_AGGR;
+	from_ipa_cfg[2].aggr.aggr = IPA_MBIM_16;
+	from_ipa_cfg[2].aggr.aggr_byte_limit = 1;
+	from_ipa_cfg[2].aggr.aggr_time_limit = 30;
+	if (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v4_2)
+		from_ipa_cfg[2].aggr.aggr_time_limit *= 1000;
+	if (mGenericAgg) {
+		from_ipa_cfg[2].hdr.hdr_len = 4;
+		from_ipa_cfg[2].hdr_ext.hdr_pad_to_alignment = 2;
+	} else {
+		from_ipa_cfg[2].hdr.hdr_len = 1;
+	}
+
+	prepare_channel_struct(&from_ipa_channels[2],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST_CONS,
+			(void *)&from_ipa_cfg[2],
+			sizeof(from_ipa_cfg[2]),
+			false);
+	from_ipa_array[2] = &from_ipa_channels[2];
+
+	memset(&from_ipa_cfg[3], 0, sizeof(from_ipa_cfg[3]));
+	from_ipa_cfg[3].aggr.aggr_en = IPA_ENABLE_AGGR;
+	from_ipa_cfg[3].aggr.aggr = IPA_MBIM_16;
+	from_ipa_cfg[3].aggr.aggr_byte_limit = 0;
+	from_ipa_cfg[3].aggr.aggr_time_limit = 0;
+	if (mGenericAgg) {
+		from_ipa_cfg[3].hdr.hdr_len = 4;
+		from_ipa_cfg[3].hdr_ext.hdr_pad_to_alignment = 2;
+	} else {
+		from_ipa_cfg[3].hdr.hdr_len = 1;
+	}
+
+	prepare_channel_struct(&from_ipa_channels[3],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST4_CONS,
+			(void *)&from_ipa_cfg[3],
+			sizeof(from_ipa_cfg[3]),
+			false);
+	from_ipa_array[3] = &from_ipa_channels[3];
+
+	/* To ipa configurations - 2 pipes */
+	memset(&to_ipa_cfg[0], 0, sizeof(to_ipa_cfg[0]));
+	prepare_channel_struct(&to_ipa_channels[0],
+			header.to_ipa_channels_num++,
+			IPA_CLIENT_TEST_PROD,
+			(void *)&to_ipa_cfg[0],
+			sizeof(to_ipa_cfg[0]));
+	to_ipa_array[0] = &to_ipa_channels[0];
+
+	memset(&to_ipa_cfg[1], 0, sizeof(to_ipa_cfg[1]));
+	to_ipa_cfg[1].aggr.aggr_en = IPA_ENABLE_DEAGGR;
+	to_ipa_cfg[1].aggr.aggr = IPA_MBIM_16;
+	prepare_channel_struct(&to_ipa_channels[1],
+			header.to_ipa_channels_num++,
+			IPA_CLIENT_TEST2_PROD,
+			(void *)&to_ipa_cfg[1],
+			sizeof(to_ipa_cfg[1]));
+	to_ipa_array[1] = &to_ipa_channels[1];
+
+	prepare_header_struct(&header, from_ipa_array, to_ipa_array);
+
+	retval = GenericConfigureScenario(&header);
+
+	return retval;
+}
+
+bool MBIMAggregationTestFixtureConf11::Setup()
+{
+	bool bRetVal = true;
+
+	//Set the configuration to support USB->IPA and IPA->USB pipes.
+	if (SetupKernelModule() != true) {
+		LOG_MSG_ERROR("fail to configure kernel module!\n");
+		return false;
+	}
+
+	//Initialize the pipe for all the tests - this will open the inode which represents the pipe.
+	bRetVal &= m_IpaToUsbPipeAgg.Init();
+	bRetVal &= m_UsbToIpaPipe.Init();
+	bRetVal &= m_IpaToUsbPipe.Init();
+	bRetVal &= m_UsbToIpaPipeDeagg.Init();
+	bRetVal &= m_IpaToUsbPipeAggTime.Init();
+	bRetVal &= m_IpaToUsbPipeAgg0Limits.Init();
+
+	if (!m_Routing.DeviceNodeIsOpened()) {
+		LOG_MSG_ERROR(
+				"Routing block is not ready for immediate commands!\n");
+		return false;
+	}
+	if (!m_Filtering.DeviceNodeIsOpened()) {
+		LOG_MSG_ERROR(
+				"Filtering block is not ready for immediate commands!\n");
+		return false;
+	}
+	if (!m_HeaderInsertion.DeviceNodeIsOpened())
+	{
+		LOG_MSG_ERROR("Header Insertion block is not ready for immediate commands!\n");
+		return false;
+	}
+	m_HeaderInsertion.Reset();// resetting this component will reset both Routing and Filtering tables.
+
+	return bRetVal;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationTestFixtureConf11::Teardown()
+{
+	//The Destroy method will close the inode.
+	m_IpaToUsbPipeAgg.Destroy();
+	m_UsbToIpaPipe.Destroy();
+	m_IpaToUsbPipe.Destroy();
+	m_UsbToIpaPipeDeagg.Destroy();
+	m_IpaToUsbPipeAggTime.Destroy();
+	m_IpaToUsbPipeAgg0Limits.Destroy();
+
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationTestFixtureConf11::Run()
+{
+	LOG_MSG_STACK("Entering Function");
+
+	// Add the relevant filtering rules
+	if (!AddRules()) {
+		LOG_MSG_ERROR("Failed adding filtering rules.");
+		return false;
+	}
+	if (!TestLogic()) {
+		LOG_MSG_ERROR("Test failed, Input and expected output mismatch.");
+		return false;
+	}
+
+	LOG_MSG_STACK("Leaving Function (Returning True)");
+	return true;
+} // Run()
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationTestFixtureConf11::AddRules1HeaderAggregation() {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[20] = "Bypass1";
+	uint32_t nTableHdl;
+	bool bRetVal = true;
+	IPAFilteringTable cFilterTable0;
+	IPAFilteringTable cFilterTable1;
+	struct ipa_flt_rule_add sFilterRuleEntry;
+	struct ipa_ioc_get_hdr sGetHeader;
+	uint8_t aHeadertoAdd[4];
+	int hdrSize;
+
+	if (mGenericAgg) {
+		hdrSize = 4;
+		aHeadertoAdd[0]= 0x49;
+		aHeadertoAdd[1] = 0x50;
+		aHeadertoAdd[2] = 0x53;
+		aHeadertoAdd[3] = 0x00;
+	} else {
+		hdrSize = 1;
+		aHeadertoAdd[0] = 0x00;
+	}
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+	memset(&sGetHeader, 0, sizeof(sGetHeader));
+
+	// Create Header:
+	// Allocate Memory, populate it, and add in to the Header Insertion.
+	struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+			sizeof(struct ipa_ioc_add_hdr)
+					+ 1 * sizeof(struct ipa_hdr_add));
+	if (!pHeaderDescriptor) {
+		LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+	// Adding Header No1.
+	strlcpy(pHeaderDescriptor->hdr[0].name, "StreamId0", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+	memcpy(pHeaderDescriptor->hdr[0].hdr, aHeadertoAdd, hdrSize); //Header's Data
+	pHeaderDescriptor->hdr[0].hdr_len = hdrSize;
+	pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+	pHeaderDescriptor->hdr[0].is_partial = false;
+	pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+	strlcpy(sGetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sGetHeader.name));
+
+
+	if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+	{
+		LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+		bRetVal = false;
+		goto bail;
+	}
+
+	if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader))
+	{
+		LOG_MSG_ERROR(" Failed");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_DEBUG("Received Header Handle = 0x%x", sGetHeader.hdl);
+
+
+	if (!CreateBypassRoutingTable(&m_Routing, m_eIP, aBypass, IPA_CLIENT_TEST2_CONS,
+			sGetHeader.hdl,&nTableHdl)) {
+		LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+		bRetVal = false;
+		goto bail;
+	}
+
+
+	LOG_MSG_INFO("Creation of bypass routing table completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST_PROD, false, 1);
+	LOG_MSG_INFO("Creation of filtering table for IPA_CLIENT_TEST_PROD completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	if (
+			((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+			!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+
+	// Creating Filtering  Rule for De-aggregation PROD
+	cFilterTable1.Init(m_eIP,IPA_CLIENT_TEST2_PROD, false, 1);
+	LOG_MSG_INFO("Creation of filtering table for IPA_CLIENT_TEST2_PROD completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable1.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	if (
+			((uint8_t)-1 == cFilterTable1.AddRuleToTable(sFilterRuleEntry)) ||
+			!m_Filtering.AddFilteringRule(cFilterTable1.GetFilteringTable())
+			)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable1.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable1.ReadRuleFromTable(0)->status);
+	}
+
+bail:
+	Free(pHeaderDescriptor);
+	LOG_MSG_STACK(
+			"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRules()
+
+bool MBIMAggregationTestFixtureConf11::AddRules1HeaderAggregation(bool bAggForceClose) {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[20] = "Bypass1";
+	uint32_t nTableHdl;
+	bool bRetVal = true;
+	IPAFilteringTable_v2 cFilterTable0;
+	IPAFilteringTable_v2 cFilterTable1;
+	struct ipa_flt_rule_add_v2 sFilterRuleEntry;
+	struct ipa_ioc_get_hdr sGetHeader;
+	uint8_t aHeadertoAdd[4];
+	int hdrSize;
+
+	if (mGenericAgg) {
+		hdrSize = 4;
+		aHeadertoAdd[0]= 0x49;
+		aHeadertoAdd[1] = 0x50;
+		aHeadertoAdd[2] = 0x53;
+		aHeadertoAdd[3] = 0x00;
+	} else {
+		hdrSize = 1;
+		aHeadertoAdd[0] = 0x00;
+	}
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+	memset(&sGetHeader, 0, sizeof(sGetHeader));
+
+	// Create Header:
+	// Allocate Memory, populate it, and add in to the Header Insertion.
+	struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+			sizeof(struct ipa_ioc_add_hdr)
+					+ 1 * sizeof(struct ipa_hdr_add));
+	if (!pHeaderDescriptor) {
+		LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+	// Adding Header No1.
+	strlcpy(pHeaderDescriptor->hdr[0].name, "StreamId0", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+	memcpy(pHeaderDescriptor->hdr[0].hdr, aHeadertoAdd, hdrSize); //Header's Data
+	pHeaderDescriptor->hdr[0].hdr_len = hdrSize;
+	pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+	pHeaderDescriptor->hdr[0].is_partial = false;
+	pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+	strlcpy(sGetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sGetHeader.name));
+
+
+	if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+	{
+		LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+		bRetVal = false;
+		goto bail;
+	}
+
+	if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader))
+	{
+		LOG_MSG_ERROR(" Failed");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_DEBUG("Received Header Handle = 0x%x", sGetHeader.hdl);
+
+
+	if (!CreateBypassRoutingTable_v2(&m_Routing, m_eIP, aBypass, IPA_CLIENT_TEST2_CONS,
+			sGetHeader.hdl, &nTableHdl, 0)) {
+		LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+		bRetVal = false;
+		goto bail;
+	}
+
+
+	LOG_MSG_INFO("Creation of bypass routing table completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST_PROD, false, 1);
+	LOG_MSG_INFO("Creation of filtering table for IPA_CLIENT_TEST_PROD completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	sFilterRuleEntry.rule.close_aggr_irq_mod = bAggForceClose;
+	if (
+			((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+			!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+
+	// Creating Filtering  Rule for De-aggregation PROD
+	cFilterTable1.Init(m_eIP,IPA_CLIENT_TEST2_PROD, false, 1);
+	LOG_MSG_INFO("Creation of filtering table for IPA_CLIENT_TEST2_PROD completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable1.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	sFilterRuleEntry.rule.close_aggr_irq_mod = bAggForceClose;
+	if (
+			((uint8_t)-1 == cFilterTable1.AddRuleToTable(sFilterRuleEntry)) ||
+			!m_Filtering.AddFilteringRule(cFilterTable1.GetFilteringTable())
+			)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable1.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable1.ReadRuleFromTable(0)->status);
+	}
+
+bail:
+	Free(pHeaderDescriptor);
+	LOG_MSG_STACK(
+			"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRules()
+
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationTestFixtureConf11::AddRulesDeaggregation() {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[20] = "Bypass1";
+	uint32_t nTableHdl;
+	bool bRetVal = true;
+	IPAFilteringTable cFilterTable0;
+	struct ipa_flt_rule_add sFilterRuleEntry;
+	struct ipa_ioc_get_hdr sGetHeader;
+	uint8_t aHeadertoAdd[4];
+	int hdrSize;
+
+	if (mGenericAgg) {
+		hdrSize = 4;
+		aHeadertoAdd[0] = 0x49;
+		aHeadertoAdd[1] = 0x50;
+		aHeadertoAdd[2] = 0x53;
+		aHeadertoAdd[3] = 0x00;
+	}
+	else {
+		hdrSize = 1;
+		aHeadertoAdd[0] = 0x00;
+	}
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+	memset(&sGetHeader, 0, sizeof(sGetHeader));
+
+	// Create Header:
+	// Allocate Memory, populate it, and add in to the Header Insertion.
+	struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+			sizeof(struct ipa_ioc_add_hdr)
+					+ 1 * sizeof(struct ipa_hdr_add));
+	if (!pHeaderDescriptor) {
+		LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+	// Adding Header No1.
+	strlcpy(pHeaderDescriptor->hdr[0].name, "StreamId0", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+	memcpy(pHeaderDescriptor->hdr[0].hdr, (void*)&aHeadertoAdd,
+			hdrSize); //Header's Data
+	pHeaderDescriptor->hdr[0].hdr_len    = hdrSize;
+	pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+	pHeaderDescriptor->hdr[0].is_partial = false;
+	pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+	strlcpy(sGetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sGetHeader.name));
+
+
+	if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+	{
+		LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+		bRetVal = false;
+		goto bail;
+	}
+
+	if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader))
+	{
+		LOG_MSG_ERROR(" Failed");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_DEBUG("Received Header Handle = 0x%x", sGetHeader.hdl);
+
+
+	if (!CreateBypassRoutingTable(&m_Routing, m_eIP, aBypass, IPA_CLIENT_TEST3_CONS,
+			sGetHeader.hdl,&nTableHdl)) {
+		LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+		bRetVal = false;
+		goto bail;
+	}
+
+
+	LOG_MSG_INFO("Creation of bypass routing table completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST2_PROD, false, 1);
+	LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	if (
+			((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+			!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+bail:
+	Free(pHeaderDescriptor);
+	LOG_MSG_STACK(
+			"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRules()
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationTestFixtureConf11::AddRules1HeaderAggregationTime() {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[20] = "Bypass1";
+	uint32_t nTableHdl;
+	bool bRetVal = true;
+	IPAFilteringTable cFilterTable0;
+	struct ipa_flt_rule_add sFilterRuleEntry;
+	struct ipa_ioc_get_hdr sGetHeader;
+	uint8_t aHeadertoAdd[4];
+	int hdrSize;
+
+	if (mGenericAgg) {
+		hdrSize = 4;
+		aHeadertoAdd[0] = 0x49;
+		aHeadertoAdd[1] = 0x50;
+		aHeadertoAdd[2] = 0x53;
+		aHeadertoAdd[3] = 0x00;
+	}
+	else {
+		hdrSize = 1;
+		aHeadertoAdd[0] = 0x00;
+	}
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+	memset(&sGetHeader, 0, sizeof(sGetHeader));
+
+	// Create Header:
+	// Allocate Memory, populate it, and add in to the Header Insertion.
+	struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+			sizeof(struct ipa_ioc_add_hdr)
+					+ 1 * sizeof(struct ipa_hdr_add));
+	if (!pHeaderDescriptor) {
+		LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+	// Adding Header No1.
+	strlcpy(pHeaderDescriptor->hdr[0].name, "StreamId0", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+	memcpy(pHeaderDescriptor->hdr[0].hdr, (void*)&aHeadertoAdd,
+			hdrSize); //Header's Data
+	pHeaderDescriptor->hdr[0].hdr_len = hdrSize;
+	pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+	pHeaderDescriptor->hdr[0].is_partial = false;
+	pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+	strlcpy(sGetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sGetHeader.name));
+
+
+	if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+	{
+		LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+		bRetVal = false;
+		goto bail;
+	}
+
+	if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader))
+	{
+		LOG_MSG_ERROR(" Failed");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_DEBUG("Received Header Handle = 0x%x", sGetHeader.hdl);
+
+
+	if (!CreateBypassRoutingTable(&m_Routing, m_eIP, aBypass, IPA_CLIENT_TEST_CONS,
+			sGetHeader.hdl,&nTableHdl)) {
+		LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+		bRetVal = false;
+		goto bail;
+	}
+
+
+	LOG_MSG_INFO("Creation of bypass routing table completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST_PROD, false, 1);
+	LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	if (
+			((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+			!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+bail:
+	Free(pHeaderDescriptor);
+	LOG_MSG_STACK(
+			"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRules()
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationTestFixtureConf11::AddRules1HeaderAggregation0Limits() {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[20] = "Bypass1";
+	uint32_t nTableHdl;
+	bool bRetVal = true;
+	IPAFilteringTable cFilterTable0;
+	struct ipa_flt_rule_add sFilterRuleEntry;
+	struct ipa_ioc_get_hdr sGetHeader;
+	uint8_t aHeadertoAdd[4];
+	int hdrSize;
+
+	if (mGenericAgg) {
+		hdrSize = 4;
+		aHeadertoAdd[0] = 0x49;
+		aHeadertoAdd[1] = 0x50;
+		aHeadertoAdd[2] = 0x53;
+		aHeadertoAdd[3] = 0x00;
+	}
+	else {
+		hdrSize = 1;
+		aHeadertoAdd[0] = 0x00;
+	}
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+	memset(&sGetHeader, 0, sizeof(sGetHeader));
+
+	// Create Header:
+	// Allocate Memory, populate it, and add in to the Header Insertion.
+	struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+			sizeof(struct ipa_ioc_add_hdr)
+					+ 1 * sizeof(struct ipa_hdr_add));
+	if (!pHeaderDescriptor) {
+		LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+	// Adding Header No1.
+	strlcpy(pHeaderDescriptor->hdr[0].name, "StreamId0", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+	memcpy(pHeaderDescriptor->hdr[0].hdr, (void*)&aHeadertoAdd,
+			hdrSize); //Header's Data
+	pHeaderDescriptor->hdr[0].hdr_len = hdrSize;
+	pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+	pHeaderDescriptor->hdr[0].is_partial = false;
+	pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+	strlcpy(sGetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sGetHeader.name));
+
+
+	if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+	{
+		LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+		bRetVal = false;
+		goto bail;
+	}
+
+	if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader))
+	{
+		LOG_MSG_ERROR(" Failed");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_DEBUG("Received Header Handle = 0x%x", sGetHeader.hdl);
+
+
+	if (!CreateBypassRoutingTable(&m_Routing, m_eIP, aBypass, IPA_CLIENT_TEST4_CONS,
+			sGetHeader.hdl,&nTableHdl)) {
+		LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+		bRetVal = false;
+		goto bail;
+	}
+
+
+	LOG_MSG_INFO("Creation of bypass routing table completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST_PROD, false, 1);
+	LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	if (
+			((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+			!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+bail:
+	Free(pHeaderDescriptor);
+	LOG_MSG_STACK(
+			"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRules()
+
+bool MBIMAggregationTestFixtureConf11::AddRulesAggDualFC(Pipe *input, Pipe *output1, Pipe *output2) {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[2][20] = {"BypassTest2", "BypassTest4"};
+	uint32_t nTableHdl[2];
+	bool bRetVal = true;
+	IPAFilteringTable_v2 cFilterTable0;
+	struct ipa_flt_rule_add_v2 sFilterRuleEntry;
+	struct ipa_ioc_get_hdr sGetHeader;
+	uint8_t aHeadertoAdd[4];
+	int hdrSize;
+
+	if (mGenericAgg) {
+		hdrSize = 4;
+		aHeadertoAdd[0]= 0x49;
+		aHeadertoAdd[1] = 0x50;
+		aHeadertoAdd[2] = 0x53;
+		aHeadertoAdd[3] = 0x00;
+	} else {
+		hdrSize = 1;
+		aHeadertoAdd[0] = 0x00;
+	}
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+	memset(&sGetHeader, 0, sizeof(sGetHeader));
+
+	// Create Header:
+	// Allocate Memory, populate it, and add in to the Header Insertion.
+	struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+		sizeof(struct ipa_ioc_add_hdr)
+		+ 1 * sizeof(struct ipa_hdr_add));
+	if (!pHeaderDescriptor) {
+		LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+	// Adding Header No1.
+	strlcpy(pHeaderDescriptor->hdr[0].name, "StreamId0", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+	memcpy(pHeaderDescriptor->hdr[0].hdr, aHeadertoAdd, hdrSize); //Header's Data
+	pHeaderDescriptor->hdr[0].hdr_len = hdrSize;
+	pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+	pHeaderDescriptor->hdr[0].is_partial = false;
+	pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+	strlcpy(sGetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sGetHeader.name));
+
+
+	if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+	{
+		LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+		bRetVal = false;
+		goto bail;
+	}
+
+	if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader))
+	{
+		LOG_MSG_ERROR(" Failed");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_DEBUG("Received Header Handle = 0x%x", sGetHeader.hdl);
+
+	if (!CreateBypassRoutingTable_v2(&m_Routing, m_eIP, aBypass[0],
+								 output1->GetClientType(),
+								 sGetHeader.hdl, &nTableHdl[0], 0)) {
+			LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+	}
+
+	if (!CreateBypassRoutingTable_v2(&m_Routing, m_eIP, aBypass[1],
+								 output2->GetClientType(),
+								 sGetHeader.hdl, &nTableHdl[1], 0)) {
+			LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+	}
+
+	LOG_MSG_INFO("Creation of bypass routing tables completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,input->GetClientType(), false, 2);
+	LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl = nTableHdl[0]; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	sFilterRuleEntry.rule.close_aggr_irq_mod = 1;
+	if (
+		((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+		!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+		)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+	// Configuring Filtering Rule No.2
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl = nTableHdl[1]; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000002; // Filter DST_IP == 127.0.0.1.
+	sFilterRuleEntry.rule.close_aggr_irq_mod = 0;
+	if (
+		((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+		!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+		)
+	{
+		LOG_MSG_ERROR ("Adding Rule (1) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl1=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(1)->status);
+	}
+
+bail:
+	Free(pHeaderDescriptor);
+	LOG_MSG_STACK(
+		"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRulesAggDualFC()
+
+bool MBIMAggregationTestFixtureConf11::AddRulesAggDualFcRoutingBased(Pipe *input, Pipe *output1, Pipe *output2) {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[2][20] = {"BypassTest2", "BypassTest4"};
+	uint32_t nTableHdl[2];
+	bool bRetVal = true;
+	IPAFilteringTable_v2 cFilterTable0;
+	struct ipa_flt_rule_add_v2 sFilterRuleEntry;
+	struct ipa_ioc_get_hdr sGetHeader;
+	uint8_t aHeadertoAdd[4];
+	int hdrSize;
+
+	if (mGenericAgg) {
+		hdrSize = 4;
+		aHeadertoAdd[0]= 0x49;
+		aHeadertoAdd[1] = 0x50;
+		aHeadertoAdd[2] = 0x53;
+		aHeadertoAdd[3] = 0x00;
+	} else {
+		hdrSize = 1;
+		aHeadertoAdd[0] = 0x00;
+	}
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+	memset(&sGetHeader, 0, sizeof(sGetHeader));
+
+	// Create Header:
+	// Allocate Memory, populate it, and add in to the Header Insertion.
+	struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+		sizeof(struct ipa_ioc_add_hdr)
+		+ 1 * sizeof(struct ipa_hdr_add));
+	if (!pHeaderDescriptor) {
+		LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+	// Adding Header No1.
+	strlcpy(pHeaderDescriptor->hdr[0].name, "StreamId0", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+	memcpy(pHeaderDescriptor->hdr[0].hdr, aHeadertoAdd, hdrSize); //Header's Data
+	pHeaderDescriptor->hdr[0].hdr_len = hdrSize;
+	pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+	pHeaderDescriptor->hdr[0].is_partial = false;
+	pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+	strlcpy(sGetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sGetHeader.name));
+
+
+	if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+	{
+		LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+		bRetVal = false;
+		goto bail;
+	}
+
+	if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader))
+	{
+		LOG_MSG_ERROR(" Failed");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_DEBUG("Received Header Handle = 0x%x", sGetHeader.hdl);
+
+	if (!CreateBypassRoutingTable_v2(&m_Routing, m_eIP, aBypass[0],
+								 output1->GetClientType(),
+								 sGetHeader.hdl, &nTableHdl[0], 1)) {
+			LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+	}
+
+	if (!CreateBypassRoutingTable_v2(&m_Routing, m_eIP, aBypass[1],
+								 output2->GetClientType(),
+								 sGetHeader.hdl, &nTableHdl[1], 0)) {
+			LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+	}
+
+	LOG_MSG_INFO("Creation of bypass routing tables completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,input->GetClientType(), false, 2);
+	LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl = nTableHdl[0]; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	sFilterRuleEntry.rule.close_aggr_irq_mod = 0;
+	if (
+		((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+		!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+		)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+	// Configuring Filtering Rule No.2
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl = nTableHdl[1]; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000002; // Filter DST_IP == 127.0.0.1.
+	sFilterRuleEntry.rule.close_aggr_irq_mod = 0;
+	if (
+		((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+		!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+		)
+	{
+		LOG_MSG_ERROR ("Adding Rule (1) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl1=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(1)->status);
+	}
+
+bail:
+	Free(pHeaderDescriptor);
+	LOG_MSG_STACK(
+		"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRulesAggDualFC()

+ 115 - 0
kernel-tests/MBIMAggregationTestFixtureConf11.h

@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "Constants.h"
+#include "Logger.h"
+#include "linux/msm_ipa.h"
+#include "TestsUtils.h"
+#include "TestBase.h"
+#include "Pipe.h"
+#include "RoutingDriverWrapper.h"
+#include "HeaderInsertion.h"
+#include "Filtering.h"
+#include "IPAFilteringTable.h"
+
+
+#define NUM_PACKETS 5
+#define NUM_PACKETS_FC 4
+#define MAX_PACKET_SIZE 1024
+#define MAX_PACKETS_IN_MBIM_TESTS 10
+#define MAX_PACKETS_IN_NDP 8
+#define MAX_NDPS_IN_PACKET 8
+
+/*This class will be the base class of MBIM Aggregation tests.
+ *Any method other than the test case itself
+ *can be declared in this Fixture thus allowing the derived classes to
+ *implement only the test case.
+ *All the test of the Aggregation uses one input and one output in DMA mode.
+ */
+class MBIMAggregationTestFixtureConf11:public TestBase
+{
+public:
+	/*This Constructor will register each instance that it creates.*/
+	MBIMAggregationTestFixtureConf11(bool generic_agg);
+
+	virtual int SetupKernelModule();
+
+	/*This method will create and initialize two Pipe object
+	 *for the USB (Ethernet) Pipes, one
+	 *for as input and the other as output.
+	 */
+	virtual bool Setup();
+
+	/*This method will destroy the pipes.*/
+	virtual bool Teardown();
+
+	virtual bool Run();
+
+	virtual bool AddRules() = 0;
+
+	virtual bool TestLogic() = 0;
+
+	bool AddRules1HeaderAggregation();
+
+	bool AddRules1HeaderAggregation(bool bAggForceClose);
+
+	bool AddRulesDeaggregation();
+
+	bool AddRules1HeaderAggregationTime();
+
+	bool AddRules1HeaderAggregation0Limits();
+
+	bool AddRulesAggDualFC(Pipe *input, Pipe *output1, Pipe *output2);
+
+	bool AddRulesAggDualFcRoutingBased(Pipe *input, Pipe *output1, Pipe *output2);
+
+	/*The client type are set from the
+	 * peripheral perspective
+	 */
+	static Pipe m_IpaToUsbPipeAgg;
+	static Pipe m_UsbToIpaPipe;
+	static Pipe m_IpaToUsbPipe;
+	static Pipe m_UsbToIpaPipeDeagg;
+	static Pipe m_IpaToUsbPipeAggTime;
+	static Pipe m_IpaToUsbPipeAgg0Limits;
+
+	static RoutingDriverWrapper m_Routing;
+	static Filtering m_Filtering;
+	static HeaderInsertion m_HeaderInsertion;
+
+protected:
+	enum ipa_ip_type m_eIP;
+	bool mGenericAgg;
+};

+ 3366 - 0
kernel-tests/MBIMAggregationTests.cpp

@@ -0,0 +1,3366 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include "hton.h" // for htonl
+#include "MBIMAggregationTestFixtureConf11.h"
+#include "Constants.h"
+#include "TestsUtils.h"
+#include "linux/msm_ipa.h"
+
+#define AGGREGATION_LOOP 4
+#define IPV4_DST_ADDR_OFFSET (16)
+
+/////////////////////////////////////////////////////////////////////////////////
+//							MBIM Aggregation scenarios                         //
+/////////////////////////////////////////////////////////////////////////////////
+
+class MBIMAggregationScenarios {
+public:
+	//MBIM Aggregation test - sends 5 packets and receives 1 aggregated packet
+	static bool MBIMAggregationTest(Pipe* input, Pipe* output, enum ipa_ip_type m_eIP);
+	//MBIM Deaggregation test - sends an aggregated packet made from 5 packets
+	//and receives 5 packets
+	static bool MBIMDeaggregationTest(Pipe* input,
+			Pipe* output, enum ipa_ip_type m_eIP);
+	//MBIM Deaggregation one packet test - sends an aggregated packet made from
+	//1 packet and receives 1 packet
+	static bool MBIMDeaggregationOnePacketTest(Pipe* input, Pipe* output, enum ipa_ip_type m_eIP);
+	//MBIM Deaggregation and Aggregation test - sends an aggregated packet made
+	//from 5 packets and receives the same aggregated packet
+	static bool MBIMDeaggregationAndAggregationTest(Pipe* input, Pipe* output, enum ipa_ip_type m_eIP);
+	//MBIM multiple Deaggregation and Aggregation test - sends 5 aggregated
+	//packets each one made of 1 packet and receives an aggregated packet made
+	//of the 5 packets
+	static bool MBIMMultipleDeaggregationAndAggregationTest(
+			Pipe* input, Pipe* output,
+			enum ipa_ip_type m_eIP);
+	//MBIM Aggregation Loop test - sends 5 packets and expects to receive 1
+	//aggregated packet a few times
+	static bool MBIMAggregationLoopTest(Pipe* input,
+			Pipe* output, enum ipa_ip_type m_eIP);
+	//MBIM Aggregation time limit test - sends 1 small packet smaller than the
+	//byte limit and receives 1 aggregated packet
+	static bool MBIMAggregationTimeLimitTest(Pipe* input, Pipe* output, enum ipa_ip_type m_eIP);
+	//MBIM Aggregation byte limit test - sends 2 packets that together are
+	//larger than the byte limit
+	static bool MBIMAggregationByteLimitTest(Pipe* input, Pipe* output, enum ipa_ip_type m_eIP);
+	static bool MBIMAggregationByteLimitTestFC(Pipe* input, Pipe* output, enum ipa_ip_type m_eIP);
+	static bool MBIMAggregationDualDpTestFC(Pipe* input, Pipe* output1, Pipe* output2, enum ipa_ip_type m_eIP);
+	//MBIM Deaggregation multiple NDP test - sends an aggregated packet made
+	//from 5 packets and 2 NDPs and receives 5 packets
+	static bool MBIMDeaggregationMultipleNDPTest(Pipe* input, Pipe* output, enum ipa_ip_type m_eIP);
+	//MBIM Aggregation 2 pipes test - sends 3 packets from one pipe and an
+	//aggregated packet made of 2 packets from another pipe and receives 1
+	//aggregated packet made of all 5 packets
+	static bool MBIMAggregation2PipesTest(Pipe* input1, Pipe* input2, Pipe* output, enum ipa_ip_type m_eIP);
+	//MBIM Aggregation time limit loop test - sends 5 small packet smaller than
+	//the byte limit and receives 5 aggregated packet
+	static bool MBIMAggregationTimeLimitLoopTest(Pipe* input, Pipe* output, enum ipa_ip_type m_eIP);
+	//MBIM Aggregation 0 limits test - sends 5 packets and expects to get each
+	//packet back aggregated (both size and time limits are 0)
+	static bool MBIMAggregation0LimitsTest(Pipe* input, Pipe* output, enum ipa_ip_type m_eIP);
+	//MBIM Aggregation multiple packets test - sends 9 packets with same stream
+	//ID and receives 1 aggregated packet with 2 NDPs
+	static bool MBIMAggregationMultiplePacketsTest(Pipe* input, Pipe* output, enum ipa_ip_type m_eIP);
+	//MBIM Aggregation different stream IDs test - sends 5 packets with
+	//different stream IDs and receives 1 aggregated packet made of 5 NDPs
+	static bool MBIMAggregationDifferentStreamIdsTest(Pipe* input, Pipe* output, enum ipa_ip_type m_eIP);
+	//MBIM Aggregation no interleaving stream IDs test - sends 5 packets with
+	//interleaving stream IDs (0, 1, 0, 1, 0) and receives 1 aggregated packet
+	//made of 5 NDPs
+	static bool MBIMAggregationNoInterleavingStreamIdsTest(
+			Pipe* input, Pipe* output,
+			enum ipa_ip_type m_eIP);
+
+private:
+	//This method will deaggregate an aggregated packet and compare the packets
+	//to the expected packets
+	static bool DeaggragateAndComparePackets(
+			Byte pAggregatedPacket[MAX_PACKET_SIZE],
+			Byte pExpectedPackets[MAX_PACKETS_IN_MBIM_TESTS][MAX_PACKET_SIZE],
+			int pPacketsSizes[MAX_PACKETS_IN_MBIM_TESTS], int nNumPackets,
+			int nAggregatedPacketSize);
+	//This method will aggregate packets
+	static void AggregatePackets(
+			Byte pAggregatedPacket[MAX_PACKET_SIZE]/*ouput*/,
+			Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE],
+			int pPacketsSizes[NUM_PACKETS], int nNumPackets,
+			int nAggregatedPacketSize);
+	//This method will aggregate packets and take into consideration their
+	//stream id to seperate them into different NDPs
+	static void AggregatePacketsWithStreamId(
+			Byte pAggregatedPacket[MAX_PACKET_SIZE]/*ouput*/,
+			Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE],
+			int pPacketsSizes[NUM_PACKETS], int nNumPackets,
+			int nAggregatedPacketSize, Byte pPacketsStreamId[NUM_PACKETS]);
+	//This method will deaggregate an aggregated packet made of one packet and
+	//compare the packet to the expected packet
+	static bool DeaggragateAndCompareOnePacket(
+			Byte pAggregatedPacket[MAX_PACKET_SIZE],
+			Byte pExpectedPacket[MAX_PACKET_SIZE], int nPacketsSize,
+			int nAggregatedPacketSize);
+	//This method will deaggregate an aggregated packet and compare the packets
+	//to the expected packets
+	static bool DeaggragateAndComparePacketsWithStreamId(
+			Byte pAggregatedPacket[MAX_PACKET_SIZE],
+			Byte pExpectedPackets[][MAX_PACKET_SIZE], int pPacketsSizes[],
+			int nNumPackets, int nAggregatedPacketSize,
+			Byte pPacketsStreamId[NUM_PACKETS]);
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMAggregationTest(
+		Pipe* input, Pipe* output, enum ipa_ip_type m_eIP)
+{
+	//The packets that will be sent
+	Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+	//The real sizes of the packets that will be sent
+	int pPacketsSizes[NUM_PACKETS];
+	//Buffer for the packet that will be received
+	Byte pReceivedPacket[2*MAX_PACKET_SIZE];
+	//Total size of all sent packets (this is the max size of the aggregated
+	//packet minus the size of the header and the NDP)
+	int nTotalPacketsSize = MAX_PACKET_SIZE - (4 * NUM_PACKETS) - 24;
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[NUM_PACKETS];
+
+	//initialize the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		if (NUM_PACKETS - 1 == i)
+			pPacketsSizes[i] = nTotalPacketsSize;
+		else
+			pPacketsSizes[i] = nTotalPacketsSize / NUM_PACKETS;
+		while (0 != pPacketsSizes[i] % 4)
+		{
+			pPacketsSizes[i]++;
+		}
+		nTotalPacketsSize -= pPacketsSizes[i];
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pPackets[i][size] = i;
+			size++;
+		}
+
+	}
+
+	//send the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+					pPacketsSizes[i]);
+		int nBytesSent = input->Send(pPackets[i], pPacketsSizes[i]);
+		if (pPacketsSizes[i] != nBytesSent)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+					"failed!\n", i, pPacketsSizes[i]);
+			return false;
+		}
+	}
+
+	//receive the aggregated packet
+	LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be there)"
+			"\n", MAX_PACKET_SIZE);
+	int nBytesReceived = output->Receive(pReceivedPacket, MAX_PACKET_SIZE);
+	if (MAX_PACKET_SIZE != nBytesReceived)
+	{
+		LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", MAX_PACKET_SIZE);
+		print_buff(pReceivedPacket, nBytesReceived);
+		return false;
+	}
+	//deaggregating the aggregated packet
+	return DeaggragateAndComparePackets(pReceivedPacket, pPackets,
+			pPacketsSizes, NUM_PACKETS, nBytesReceived);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMDeaggregationTest(
+		Pipe* input, Pipe* output, enum ipa_ip_type m_eIP)
+{
+	bool bTestResult = true;
+	//The packets that the aggregated packet will be made of
+	Byte pExpectedPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+	//The real sizes of the packets that the aggregated packet will be made of
+	int pPacketsSizes[NUM_PACKETS];
+	//Buffers for the packets that will be received
+	Byte pReceivedPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+	//Total size of all the packets that the aggregated packet will be made of
+	//(this is the max size of the aggregated packet
+	//minus the size of the header and the NDP)
+	int nTotalPacketsSize = MAX_PACKET_SIZE - (4 * NUM_PACKETS) - 24;
+	//The aggregated packet that will be sent
+	Byte pAggregatedPacket[MAX_PACKET_SIZE] = {0};
+
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[NUM_PACKETS];
+
+	//initialize the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		if (NUM_PACKETS - 1 == i)
+			pPacketsSizes[i] = nTotalPacketsSize;
+		else
+			pPacketsSizes[i] = nTotalPacketsSize / NUM_PACKETS;
+		while (0 != pPacketsSizes[i] % 4)
+		{
+			pPacketsSizes[i]++;
+		}
+		nTotalPacketsSize -= pPacketsSizes[i];
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pExpectedPackets[i],
+				pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pExpectedPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pExpectedPackets[i][size] = i;
+			size++;
+		}
+	}
+
+	//initializing the aggregated packet
+	AggregatePackets(pAggregatedPacket, pExpectedPackets, pPacketsSizes,
+			NUM_PACKETS, MAX_PACKET_SIZE);
+
+	//send the aggregated packet
+	LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d bytes)\n",
+			sizeof(pAggregatedPacket));
+	int nBytesSent = input->Send(pAggregatedPacket, sizeof(pAggregatedPacket));
+	if (sizeof(pAggregatedPacket) != nBytesSent)
+	{
+		LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d bytes) "
+				"failed!\n", sizeof(pAggregatedPacket));
+		return false;
+	}
+
+	//receive the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		LOG_MSG_DEBUG("Reading packet %d from the USB pipe(%d bytes should be "
+				"there)\n", i, pPacketsSizes[i]);
+		int nBytesReceived = output->Receive(pReceivedPackets[i],
+				pPacketsSizes[i]);
+		if (pPacketsSizes[i] != nBytesReceived)
+		{
+			LOG_MSG_DEBUG("Receiving packet %d from the USB pipe(%d bytes) "
+					"failed!\n", i, pPacketsSizes[i]);
+			print_buff(pReceivedPackets[i], nBytesReceived);
+			return false;
+		}
+	}
+
+	//comparing the received packet to the aggregated packet
+	LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+	for (int i = 0; i < NUM_PACKETS; i++)
+		bTestResult &= !memcmp(pExpectedPackets[i], pReceivedPackets[i],
+				pPacketsSizes[i]);
+
+	return bTestResult;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMDeaggregationOnePacketTest(
+		Pipe* input, Pipe* output,
+		enum ipa_ip_type m_eIP)
+{
+	bool bTestResult = true;
+	//The packets that the aggregated packet will be made of
+	Byte pExpectedPackets[1][MAX_PACKET_SIZE];
+	//The real sizes of the packets that the aggregated packet will be made of
+	int pPacketsSizes[1] = {100};
+	//Buffers for the packets that will be received
+	Byte pReceivedPackets[1][MAX_PACKET_SIZE];
+	//Total size of the aggregated packet
+	//(this is the max size of the aggregated packet
+	//minus the size of the header and the NDP)
+	int nTotalAggregatedPacketSize = 100 + 12 + 16;
+	//The aggregated packet that will be sent
+	Byte pAggregatedPacket[MAX_PACKET_SIZE] = {0};
+
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[1];
+
+	// Load input data (IP packet) from file
+	pIpPacketsSizes[0] = 100;
+	if (!LoadDefaultPacket(m_eIP, pExpectedPackets[0], pIpPacketsSizes[0]))
+	{
+		LOG_MSG_ERROR("Failed default Packet");
+		return false;
+	}
+	nIPv4DSTAddr = ntohl(0x7F000001);
+	memcpy (&pExpectedPackets[0][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+	int size = pIpPacketsSizes[0];
+	while (size < pPacketsSizes[0])
+	{
+		pExpectedPackets[0][size] = 0;
+		size++;
+	}
+
+
+	//initializing the aggregated packet
+	AggregatePackets(pAggregatedPacket, pExpectedPackets, pPacketsSizes, 1,
+			nTotalAggregatedPacketSize);
+
+	//send the aggregated packet
+	LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d bytes)\n",
+			nTotalAggregatedPacketSize);
+	int nBytesSent = input->Send(pAggregatedPacket, nTotalAggregatedPacketSize);
+	if (nTotalAggregatedPacketSize != nBytesSent)
+	{
+		LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d bytes) "
+				"failed!\n", nTotalAggregatedPacketSize);
+		return false;
+	}
+
+	//receive the packet
+	for (int i = 0; i < 1; i++)
+	{
+		LOG_MSG_DEBUG("Reading packet %d from the USB pipe(%d bytes should be "
+				"there)\n", i, pPacketsSizes[i]);
+		int nBytesReceived = output->Receive(pReceivedPackets[i],
+				pPacketsSizes[i]);
+		if (pPacketsSizes[i] != nBytesReceived)
+		{
+			LOG_MSG_DEBUG("Receiving packet %d from the USB pipe(%d bytes) "
+					"failed!\n", i, pPacketsSizes[i]);
+			print_buff(pReceivedPackets[i], nBytesReceived);
+			return false;
+		}
+	}
+
+	//comparing the received packet to the aggregated packet
+	LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+	for (int i = 0; i < 1; i++)
+		bTestResult &= !memcmp(pExpectedPackets[i], pReceivedPackets[i],
+				pPacketsSizes[i]);
+
+	return bTestResult;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMDeaggregationAndAggregationTest(
+		Pipe* input, Pipe* output,
+		enum ipa_ip_type m_eIP)
+{
+	//The packets that the aggregated packet will be made of
+	Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+	//The real sizes of the packets that the aggregated packet will be made of
+	int pPacketsSizes[NUM_PACKETS];
+	//Buffers for the packets that will be received
+	Byte pReceivedPacket[MAX_PACKET_SIZE];
+	//Total size of all the packets that the aggregated packet will be made of
+	//(this is the max size of the aggregated packet
+	//minus the size of the header and the NDP)
+	int nTotalPacketsSize = MAX_PACKET_SIZE - (4 * NUM_PACKETS) - 24;
+	//The aggregated packet that will be sent
+	Byte pAggregatedPacket[MAX_PACKET_SIZE] = {0};
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[NUM_PACKETS];
+
+	//initialize the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		if (NUM_PACKETS - 1 == i)
+			pPacketsSizes[i] = nTotalPacketsSize;
+		else
+			pPacketsSizes[i] = nTotalPacketsSize / NUM_PACKETS;
+		while (0 != pPacketsSizes[i] % 4)
+			pPacketsSizes[i]++;
+		nTotalPacketsSize -= pPacketsSizes[i];
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pPackets[i][size] = i;
+			size++;
+		}
+	}
+
+	//initializing the aggregated packet
+	AggregatePackets(pAggregatedPacket, pPackets, pPacketsSizes, NUM_PACKETS,
+			MAX_PACKET_SIZE);
+
+	//send the aggregated packet
+	LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d bytes)\n",
+			MAX_PACKET_SIZE);
+	int nBytesSent = input->Send(pAggregatedPacket, MAX_PACKET_SIZE);
+	if (MAX_PACKET_SIZE != nBytesSent)
+	{
+		LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d bytes) "
+				"failed!\n", MAX_PACKET_SIZE);
+		return false;
+	}
+
+	//receive the aggregated packet
+	LOG_MSG_DEBUG("Reading aggregated packet from the USB pipe(%d bytes should "
+			"be there)\n", MAX_PACKET_SIZE);
+	int nBytesReceived = output->Receive(pReceivedPacket, MAX_PACKET_SIZE);
+	if (MAX_PACKET_SIZE != nBytesReceived)
+	{
+		LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", MAX_PACKET_SIZE);
+		LOG_MSG_DEBUG("Received %d bytes\n", nBytesReceived);
+		print_buff(pReceivedPacket, nBytesReceived);
+		return false;
+	}
+
+
+	//comparing the received packet to the aggregated packet
+	LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+	return DeaggragateAndComparePackets(pReceivedPacket, pPackets, pPacketsSizes,
+			NUM_PACKETS, nBytesReceived);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMMultipleDeaggregationAndAggregationTest(
+		Pipe* input, Pipe* output,
+		enum ipa_ip_type m_eIP)
+{
+	//The packets that the aggregated packets will be made of
+	Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+	//The real sizes of the packets that the aggregated packet will be made of
+	int pPacketsSizes[NUM_PACKETS];
+	//Buffers for the packets that will be received
+	Byte pReceivedPacket[MAX_PACKET_SIZE];
+	//Total size of all the packets that the aggregated packet will be made of
+	//(this is the max size of the aggregated packet
+	//minus the size of the header and the NDP)
+	int nTotalPacketsSize = MAX_PACKET_SIZE - (4 * NUM_PACKETS) - 24;
+	//The aggregated packet that will be sent
+	Byte pAggregatedPacket[NUM_PACKETS][MAX_PACKET_SIZE];
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[NUM_PACKETS];
+
+	//initialize the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		if (NUM_PACKETS - 1 == i)
+			pPacketsSizes[i] = nTotalPacketsSize;
+		else
+			pPacketsSizes[i] = nTotalPacketsSize / NUM_PACKETS;
+		while (0 != pPacketsSizes[i] % 4)
+			pPacketsSizes[i]++;
+		nTotalPacketsSize -= pPacketsSizes[i];
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pPackets[i][size] = i;
+			size++;
+		}
+
+	}
+
+	//initializing the aggregated packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+		AggregatePackets(pAggregatedPacket[i], &pPackets[i], &pPacketsSizes[i],
+				1, pPacketsSizes[i] + 12 + 16);
+
+	//send the aggregated packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		LOG_MSG_DEBUG("Sending aggregated packet %d into the USB pipe(%d "
+				"bytes)\n", i, pPacketsSizes[i] + 12 + 16);
+		int nBytesSent = input->Send(pAggregatedPacket[i],
+				pPacketsSizes[i] + 12 + 16);
+		if (pPacketsSizes[i] + 12 + 16 != nBytesSent)
+		{
+			LOG_MSG_DEBUG("Sending aggregated packet %d into the USB pipe(%d "
+					"bytes) failed!\n", i, pPacketsSizes[i] + 12 + 16);
+			return false;
+		}
+	}
+
+	//receive the aggregated packet
+	LOG_MSG_DEBUG("Reading aggregated packet from the USB pipe(%d bytes should "
+			"be there)\n", MAX_PACKET_SIZE);
+	int nBytesReceived = output->Receive(pReceivedPacket, MAX_PACKET_SIZE);
+	if (MAX_PACKET_SIZE != nBytesReceived)
+	{
+		LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", MAX_PACKET_SIZE);
+		LOG_MSG_DEBUG("Received %d bytes\n", nBytesReceived);
+		print_buff(pReceivedPacket, nBytesReceived);
+		return false;
+	}
+
+
+	//comparing the received packet to the aggregated packet
+	LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+	return DeaggragateAndComparePackets(pReceivedPacket, pPackets,
+			pPacketsSizes, NUM_PACKETS, nBytesReceived);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMAggregationLoopTest(
+		Pipe* input, Pipe* output, enum ipa_ip_type m_eIP)
+{
+	//The packets that will be sent
+	Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+	//The real sizes of the packets that will be sent
+	int pPacketsSizes[NUM_PACKETS];
+	//Buffer for the packet that will be received
+	Byte pReceivedPacket[MAX_PACKET_SIZE];
+	//Total size of all sent packets (this is the max size of the aggregated
+	//packet minus the size of the header and the NDP)
+	int nTotalPacketsSize = MAX_PACKET_SIZE - (4 * NUM_PACKETS) - 24;
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[NUM_PACKETS];
+
+	//initialize the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		if (NUM_PACKETS - 1 == i)
+			pPacketsSizes[i] = nTotalPacketsSize;
+		else
+			pPacketsSizes[i] = nTotalPacketsSize / NUM_PACKETS;
+		while (0 != pPacketsSizes[i] % 4)
+			pPacketsSizes[i]++;
+		nTotalPacketsSize -= pPacketsSizes[i];
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pPackets[i][size] = i;
+			size++;
+		}
+	}
+
+	int num_iters = AGGREGATION_LOOP - 1;
+	for (int j = 0; j < num_iters; j++)
+	{
+		//send the packets
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+					pPacketsSizes[i]);
+			int nBytesSent = input->Send(pPackets[i], pPacketsSizes[i]);
+			if (pPacketsSizes[i] != nBytesSent)
+			{
+				LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+						"failed!\n", i, pPacketsSizes[i]);
+				return false;
+			}
+		}
+
+		memset(pReceivedPacket, 0, sizeof(pReceivedPacket));
+		//receive the aggregated packet
+		LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be "
+				"there)\n", MAX_PACKET_SIZE);
+		int nBytesReceived = output->Receive(pReceivedPacket, MAX_PACKET_SIZE);
+		if (MAX_PACKET_SIZE != nBytesReceived)
+		{
+			LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d "
+					"bytes) failed!\n", MAX_PACKET_SIZE);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+
+		LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+		if (false == DeaggragateAndComparePackets(pReceivedPacket, pPackets,
+				pPacketsSizes, NUM_PACKETS, nBytesReceived))
+		{
+			LOG_MSG_DEBUG("Comparing aggregated packet failed!\n");
+			return false;
+		}
+
+	}
+
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMAggregationTimeLimitTest(
+		Pipe* input, Pipe* output,
+		enum ipa_ip_type m_eIP)
+{
+	//The packets that will be sent
+	Byte pPackets[1][MAX_PACKET_SIZE];
+	//The real sizes of the packets that will be sent
+	int pPacketsSizes[1] = {0};
+	//Buffer for the packet that will be received
+	Byte pReceivedPacket[MAX_PACKET_SIZE] = {0};
+	//Size of aggregated packet
+	int nTotalPacketsSize = 24;
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[1];
+
+	//initialize the packets
+	for (int i = 0; i < 1 ; i++)
+	{
+		pPacketsSizes[i] = 52 + 4*i;
+		nTotalPacketsSize += pPacketsSizes[i] + 4; //size of the packet + 4 bytes for index and length
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pPackets[i][size] = i;
+			size++;
+		}
+	}
+	int nAllPacketsSizes = 0;
+	for (int i = 0; i < 1; i++)
+		nAllPacketsSizes += pPacketsSizes[i];
+	while (0 != nAllPacketsSizes % 4)
+	{
+		nAllPacketsSizes++;
+		nTotalPacketsSize++;  //zero padding for NDP offset to be 4x
+	}
+
+	//send the packets
+	for (int i = 0; i < 1; i++)
+	{
+		LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+				pPacketsSizes[i]);
+		int nBytesSent = input->Send(pPackets[i], pPacketsSizes[i]);
+		if (pPacketsSizes[i] != nBytesSent)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+					"failed!\n", i, pPacketsSizes[i]);
+			return false;
+		}
+	}
+
+	//receive the aggregated packet
+	LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be "
+			"there)\n", nTotalPacketsSize);
+	int nBytesReceived = output->Receive(pReceivedPacket, nTotalPacketsSize);
+	// IPA HW may add padding to the packets to align to 4B
+	if (nTotalPacketsSize > nBytesReceived)
+	{
+		LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", nTotalPacketsSize);
+		print_buff(pReceivedPacket, nBytesReceived);
+		return false;
+	}
+
+	//comparing the received packet to the aggregated packet
+	LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+	if (false == DeaggragateAndComparePackets(pReceivedPacket, pPackets,
+			pPacketsSizes, 1, nBytesReceived))
+	{
+		LOG_MSG_DEBUG("Comparing aggregated packet failed!\n");
+		print_buff(pReceivedPacket, nBytesReceived);
+		return false;
+	}
+
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMAggregationByteLimitTest(
+		Pipe* input, Pipe* output,
+		enum ipa_ip_type m_eIP)
+{
+	//The packets that will be sent
+	Byte pPackets[2][MAX_PACKET_SIZE];
+	//The real sizes of the packets that will be sent
+	int pPacketsSizes[2];
+	//Buffer for the packet that will be received
+	Byte pReceivedPacket[2*MAX_PACKET_SIZE] = {0};
+	//Size of aggregated packet
+	int nTotalPacketsSize = 24;
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[2];
+
+	//initialize the packets
+	for (int i = 0; i < 2; i++)
+	{
+		pPacketsSizes[i] = (MAX_PACKET_SIZE / 2) + 10;
+		nTotalPacketsSize += pPacketsSizes[i] + 4;
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pPackets[i][size] = i;
+			size++;
+		}
+	}
+
+
+	//send the packets
+	for (int i = 0; i < 2; i++)
+	{
+		LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+				pPacketsSizes[i]);
+		int nBytesSent = input->Send(pPackets[i], pPacketsSizes[i]);
+		if (pPacketsSizes[i] != nBytesSent)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+					"failed!\n", i, pPacketsSizes[i]);
+			return false;
+		}
+	}
+
+	//receive the aggregated packet
+	LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be "
+			"there)\n", nTotalPacketsSize);
+	int nBytesReceived = output->Receive(pReceivedPacket, nTotalPacketsSize);
+	// IPA HW may add padding to the packets to align to 4B
+	if (nTotalPacketsSize > nBytesReceived)
+	{
+		LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", nTotalPacketsSize);
+		print_buff(pReceivedPacket, nBytesReceived);
+		return false;
+	}
+
+	//comparing the received packet to the aggregated packet
+	LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+	if (false == DeaggragateAndComparePackets(pReceivedPacket, pPackets,
+			pPacketsSizes, 2, nBytesReceived))
+	{
+		LOG_MSG_DEBUG("Comparing aggregated packet failed!\n");
+		return false;
+	}
+
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMAggregationByteLimitTestFC(
+	Pipe *input, Pipe *output,
+	enum ipa_ip_type m_eIP)
+{
+	//The packets that will be sent
+	Byte pPackets[2][MAX_PACKET_SIZE];
+	//The real sizes of the packets that will be sent
+	int pPacketsSizes[2];
+	//Buffer for the packet that will be received
+	Byte pReceivedPacket[2][MAX_PACKET_SIZE] = {0};
+	//Size of aggregated packet
+	int nTotalPacketsSize = 24 + (MAX_PACKET_SIZE / 2) + 8 + 4;
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[2];
+	int nBytesReceived;
+
+	for (int i = 0; i < 2; i++)
+	{
+		pPacketsSizes[i] = (MAX_PACKET_SIZE / 2) + 8;
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pPackets[i][size] = i;
+			size++;
+		}
+	}
+
+
+	//send the packets
+	for (int i = 0; i < 2; i++)
+	{
+		LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+				pPacketsSizes[i]);
+		int nBytesSent = input->Send(pPackets[i], pPacketsSizes[i]);
+		if (pPacketsSizes[i] != nBytesSent)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+					"failed!\n", i, pPacketsSizes[i]);
+			return false;
+		}
+	}
+
+	/* receive the packet */
+	LOG_MSG_DEBUG(
+		"Reading packets from the USB pipe(%d bytes for each)"
+		"\n", nTotalPacketsSize);
+	for (int i = 0; i < 2; i++)
+	{
+		nBytesReceived = output->Receive(pReceivedPacket[i], MAX_PACKET_SIZE);
+		if (nTotalPacketsSize != nBytesReceived)
+		{
+			LOG_MSG_ERROR(
+				"Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", nBytesReceived);
+			print_buff(pReceivedPacket[i], nBytesReceived);
+			return false;
+		}
+	}
+
+	//comparing the received packets to the aggregated packets
+	LOG_MSG_DEBUG("Checking sent.vs.received packets\n");
+	for (int i = 0; i < 2; i++)
+	{
+		if (false == DeaggragateAndComparePackets(pReceivedPacket[i],
+							  &pPackets[i],
+							  (int *)&pPacketsSizes[i],
+							  1,
+							  nBytesReceived))
+		{
+			LOG_MSG_DEBUG("Comparing aggregated packet failed!\n");
+			return false;
+		}
+	}
+
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+#define DUAL_FC_IP_PACKET_L ((MAX_PACKET_SIZE / 2) + 8)
+#define DUAL_FC_1_AGG_PACKET_L (12 + DUAL_FC_IP_PACKET_L + 12 + 4)
+#define DUAL_FC_2_AGG_PACKET_L (12 + DUAL_FC_IP_PACKET_L + DUAL_FC_IP_PACKET_L + 12 + 4 + 4)
+bool MBIMAggregationScenarios::MBIMAggregationDualDpTestFC(
+	Pipe *input, Pipe *output1, Pipe *output2,
+	enum ipa_ip_type m_eIP)
+{
+	int i;
+	//The packets that will be sent
+	Byte pPackets[4][MAX_PACKET_SIZE];
+	//The real sizes of the packets that will be sent
+	int pPacketsSizes[4];
+	//Buffer for the packet that will be received
+	Byte pReceivedPacket[2 * MAX_PACKET_SIZE] = {0};
+	Byte pReceivedPacketFC[2][MAX_PACKET_SIZE] = {0};
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[4];
+	int nBytesReceived;
+
+	for (i = 0; i < 4; i++)
+	{
+		pPacketsSizes[i] = DUAL_FC_IP_PACKET_L;
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001 + (i & 0x1));
+		memcpy(&pPackets[i][IPV4_DST_ADDR_OFFSET], &nIPv4DSTAddr,
+		       sizeof(nIPv4DSTAddr));
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pPackets[i][size] = 0xAA;
+			size++;
+		}
+	}
+
+	//send the packets
+	for (int i = 0; i < 4; i++)
+	{
+		LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+				pPacketsSizes[i]);
+		int nBytesSent = input->Send(pPackets[i], pPacketsSizes[i]);
+		if (pPacketsSizes[i] != nBytesSent)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+					"failed!\n", i, pPacketsSizes[i]);
+			return false;
+		}
+	}
+
+	/* receive the packets from FC pipe */
+	LOG_MSG_DEBUG(
+		"Reading packets from the FC pipe (%d bytes for each)"
+		"\n", DUAL_FC_1_AGG_PACKET_L);
+	for (i = 0; i < 2; i++)
+	{
+		nBytesReceived = output1->Receive(pReceivedPacketFC[i], MAX_PACKET_SIZE);
+		if (DUAL_FC_1_AGG_PACKET_L != nBytesReceived)
+		{
+			LOG_MSG_ERROR(
+				"Receiving aggregated packet from the USB pipe (%d bytes) "
+				"failed!\n", nBytesReceived);
+			print_buff(pReceivedPacketFC[i], nBytesReceived);
+			return false;
+		}
+	}
+
+	for (i = 0; i < 2; i++)
+	{
+		if (false == DeaggragateAndComparePackets(pReceivedPacketFC[i],
+							  &pPackets[i * 2],
+							  (int *)&pPacketsSizes[i * 2],
+							  1,
+							  nBytesReceived))
+		{
+			LOG_MSG_DEBUG("Comparing aggregated packet failed!\n");
+			return false;
+		}
+	}
+
+	/* receive the packet from non-FC pipe */
+	LOG_MSG_DEBUG(
+		"Reading packet from the non-FC pipe (%d bytes)"
+		"\n", DUAL_FC_2_AGG_PACKET_L);
+	nBytesReceived = output2->Receive(pReceivedPacket, MAX_PACKET_SIZE);
+	if (DUAL_FC_2_AGG_PACKET_L != nBytesReceived)
+	{
+		LOG_MSG_ERROR(
+			"Receiving aggregated packet from the USB pipe (%d bytes) "
+			"failed!\n", nBytesReceived);
+		print_buff(pReceivedPacket, nBytesReceived);
+		return false;
+	}
+
+	// Setting all source packets IP to 127.0.0.2 for comparison
+	nIPv4DSTAddr = ntohl(0x7F000002);
+	memcpy(&pPackets[0][IPV4_DST_ADDR_OFFSET], &nIPv4DSTAddr, sizeof(nIPv4DSTAddr));
+	memcpy(&pPackets[2][IPV4_DST_ADDR_OFFSET], &nIPv4DSTAddr, sizeof(nIPv4DSTAddr));
+
+	if (false == DeaggragateAndComparePackets(&pReceivedPacket[0], pPackets,
+			(int *)&pPacketsSizes, 2, nBytesReceived))
+	{
+		LOG_MSG_DEBUG("Comparing aggregated packet failed!\n");
+		print_buff(pReceivedPacket, nBytesReceived);
+		return false;
+	}
+
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMDeaggregationMultipleNDPTest(
+		Pipe* input, Pipe* output,
+		enum ipa_ip_type m_eIP)
+{
+	bool bTestResult = true;
+	//The packets that the aggregated packet will be made of
+	Byte pExpectedPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+	//The real sizes of the packets that the aggregated packet will be made of
+	int pPacketsSizes[NUM_PACKETS];
+	//Buffers for the packets that will be received
+	Byte pReceivedPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+	//Total size of all the packets that the aggregated packet will be made of
+	//(this is the max size of the aggregated packet
+	//minus the size of the header and the 2 NDPs)
+	int nTotalPacketsSize = MAX_PACKET_SIZE - (4 * NUM_PACKETS) - 36;
+	//The aggregated packet that will be sent
+	Byte pAggregatedPacket[MAX_PACKET_SIZE] = {0};
+	//The stream Id byte for every packet - this will determine on which NDP the
+	//packet will appear
+	Byte pPacketsStreamId[NUM_PACKETS] = {0};
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[NUM_PACKETS];
+
+	//initialize the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		if (NUM_PACKETS - 1 == i)
+			pPacketsSizes[i] = nTotalPacketsSize;
+		else {
+			pPacketsSizes[i] = nTotalPacketsSize / NUM_PACKETS;
+			pPacketsSizes[i] += (pPacketsSizes[i] % 4 == 0 ? 0 :
+				4 - pPacketsSizes[i] % 4);
+		}
+		nTotalPacketsSize -= pPacketsSizes[i];
+		pPacketsStreamId[i] = i < 3 ? 0 : 1;
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pExpectedPackets[i],
+				pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pExpectedPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pExpectedPackets[i][size] = i;
+			size++;
+		}
+	}
+
+	//initializing the aggregated packet
+	AggregatePacketsWithStreamId(pAggregatedPacket, pExpectedPackets,
+			pPacketsSizes, NUM_PACKETS, MAX_PACKET_SIZE, pPacketsStreamId);
+
+	//send the aggregated packet
+	LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d bytes)\n",
+			sizeof(pAggregatedPacket));
+	int nBytesSent = input->Send(pAggregatedPacket, sizeof(pAggregatedPacket));
+	if (sizeof(pAggregatedPacket) != nBytesSent)
+	{
+		LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d bytes) "
+				"failed!\n", sizeof(pAggregatedPacket));
+		return false;
+	}
+
+	//receive the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		LOG_MSG_DEBUG("Reading packet %d from the USB pipe(%d bytes should be "
+				"there)\n", i, pPacketsSizes[i]);
+		int nBytesReceived = output->Receive(pReceivedPackets[i],
+				pPacketsSizes[i]);
+		if (pPacketsSizes[i] != nBytesReceived)
+		{
+			LOG_MSG_DEBUG("Receiving packet %d from the USB pipe(%d bytes) "
+					"failed!\n", i, pPacketsSizes[i]);
+			print_buff(pReceivedPackets[i], nBytesReceived);
+			return false;
+		}
+	}
+
+	//comparing the received packet to the aggregated packet
+	LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+	for (int i = 0; i < NUM_PACKETS; i++)
+		bTestResult &= !memcmp(pExpectedPackets[i], pReceivedPackets[i],
+				pPacketsSizes[i]);
+
+	return bTestResult;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMAggregation2PipesTest(
+		Pipe* input1, Pipe* input2, Pipe* output, enum ipa_ip_type m_eIP)
+{
+	//The packets that will be sent
+	Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+	//The real sizes of the packets that will be sent
+	int pPacketsSizes[NUM_PACKETS];
+	//Buffer for the packet that will be received
+	Byte pReceivedPacket[2*MAX_PACKET_SIZE];
+	//Total size of all sent packets (this is the max size of the aggregated
+	//packet minus the size of the header and the NDP)
+	int nTotalPacketsSize = MAX_PACKET_SIZE - (4 * NUM_PACKETS) - 24;
+	//The aggregated packet that will be sent
+	Byte pAggregatedPacket[2][MAX_PACKET_SIZE];
+	//The size of the sent aggregated packet
+	int nAggregatedPacketSize[2] = {0};
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[NUM_PACKETS];
+
+	//initialize the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		if (NUM_PACKETS - 1 == i)
+			pPacketsSizes[i] = nTotalPacketsSize;
+		else
+			pPacketsSizes[i] = nTotalPacketsSize / NUM_PACKETS;
+		while (0 != pPacketsSizes[i] % 4)
+			pPacketsSizes[i]++;
+		nTotalPacketsSize -= pPacketsSizes[i];
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pPackets[i][size] = i;
+			size++;
+		}
+	}
+
+
+	nAggregatedPacketSize[0] += pPacketsSizes[0] + pPacketsSizes[1]; //adding the packets
+	nAggregatedPacketSize[0] += 12;  //adding the header
+	nAggregatedPacketSize[0] += 12 + 4*2; //adding the NDP
+	//initializing the aggregated packet
+	AggregatePackets(pAggregatedPacket[0], pPackets, pPacketsSizes, 2,
+			nAggregatedPacketSize[0]);
+
+	//send the aggregated packet
+
+	LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d "
+		"bytes)\n", nAggregatedPacketSize[0]);
+	int nBytesSent = input1->Send(pAggregatedPacket[0],
+		nAggregatedPacketSize[0]);
+	if (nAggregatedPacketSize[0] != nBytesSent)
+	{
+		LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d bytes) "
+			"failed!\n", nAggregatedPacketSize[0]);
+		return false;
+	}
+
+	//send the packets
+	for (int i = 2; i < NUM_PACKETS; i++)
+	{
+		LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+				pPacketsSizes[i]);
+		int nBytesSent = input2->Send(pPackets[i], pPacketsSizes[i]);
+		if (pPacketsSizes[i] != nBytesSent)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+					"failed!\n", i, pPacketsSizes[i]);
+			return false;
+		}
+	}
+
+	//receive the aggregated packet
+	LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be "
+			"there)\n", MAX_PACKET_SIZE);
+	int nBytesReceived = output->Receive(pReceivedPacket, MAX_PACKET_SIZE);
+	if (MAX_PACKET_SIZE != nBytesReceived)
+	{
+		LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", MAX_PACKET_SIZE);
+		print_buff(pReceivedPacket, nBytesReceived);
+		return false;
+	}
+
+	//deaggregating the aggregated packet
+	return DeaggragateAndComparePackets(pReceivedPacket, pPackets, pPacketsSizes, NUM_PACKETS, nBytesReceived);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMAggregationTimeLimitLoopTest(
+		Pipe* input, Pipe* output,
+		enum ipa_ip_type m_eIP)
+{
+	//The packets that will be sent
+	Byte pPackets[1][MAX_PACKET_SIZE];
+	//The real sizes of the packets that will be sent
+	int pPacketsSizes[1] = {0};
+	//Buffer for the packet that will be received
+	Byte pReceivedPacket[MAX_PACKET_SIZE] = {0};
+	//Size of aggregated packet
+	int nTotalPacketsSize = 24;
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[NUM_PACKETS];
+
+	//initialize the packets
+	for (int i = 0; i < 1 ; i++)
+	{
+		pPacketsSizes[i] = 52 + 4*i;
+		nTotalPacketsSize += pPacketsSizes[i] + 4; //size of the packet + 4 bytes for index and length
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pPackets[i][size] = i;
+			size++;
+		}
+	}
+	int nAllPacketsSizes = 0;
+	for (int i = 0; i < 1; i++)
+		nAllPacketsSizes += pPacketsSizes[i];
+	while (0 != nAllPacketsSizes % 4)
+	{
+		nAllPacketsSizes++;
+		nTotalPacketsSize++;  //zero padding for NDP offset to be 4x
+	}
+
+	for (int k = 0; k < AGGREGATION_LOOP; k++)
+	{
+		//send the packets
+		for (int i = 0; i < 1; i++)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+					pPacketsSizes[i]);
+			int nBytesSent = input->Send(pPackets[i], pPacketsSizes[i]);
+			if (pPacketsSizes[i] != nBytesSent)
+			{
+				LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+						"failed!\n", i, pPacketsSizes[i]);
+				return false;
+			}
+		}
+
+		//receive the aggregated packet
+		LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be "
+				"there)\n", nTotalPacketsSize);
+		int nBytesReceived = output->Receive(pReceivedPacket,
+				nTotalPacketsSize);
+		// IPA HW may add padding to the packets to align to 4B
+		if (nTotalPacketsSize > nBytesReceived)
+		{
+			LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d "
+					"bytes) failed!\n", nTotalPacketsSize);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+
+		//comparing the received packet to the aggregated packet
+		LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+		if (false == DeaggragateAndComparePackets(pReceivedPacket, pPackets,
+				pPacketsSizes, 1, nBytesReceived))
+		{
+			LOG_MSG_DEBUG("Comparing aggregated packet failed!\n");
+			return false;
+		}
+	}
+
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMAggregation0LimitsTest(
+		Pipe* input, Pipe* output,
+		enum ipa_ip_type m_eIP)
+{
+	//The packets that will be sent
+	Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+	//The real sizes of the packets that will be sent
+	int pPacketsSizes[NUM_PACKETS];
+	//Buffer for the packet that will be received
+	Byte pReceivedPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+	//The expected aggregated packets sizes
+	int pAggragatedPacketsSizes[NUM_PACKETS] = {0};
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[NUM_PACKETS];
+
+	//initialize the packets
+	for (int i = 0; i < NUM_PACKETS ; i++)
+	{
+		pPacketsSizes[i] = 52 + 4*i;
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pPackets[i][size] = i;
+			size++;
+		}
+	}
+
+	//calculate aggregated packets sizes
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		pAggragatedPacketsSizes[i] += pPacketsSizes[i];
+		while (0 != pAggragatedPacketsSizes[i] % 4)
+			pAggragatedPacketsSizes[i]++;  //zero padding for NDP offset to be 4x
+		pAggragatedPacketsSizes[i] += 28;  //header + NDP
+	}
+
+	//send the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+				pPacketsSizes[i]);
+		int nBytesSent = input->Send(pPackets[i], pPacketsSizes[i]);
+		if (pPacketsSizes[i] != nBytesSent)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+					"failed!\n", i, pPacketsSizes[i]);
+			return false;
+		}
+	}
+
+	//receive the aggregated packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		LOG_MSG_DEBUG("Reading packet %d from the USB pipe(%d bytes should be "
+				"there)\n", i, pAggragatedPacketsSizes[i]);
+		int nBytesReceived = output->Receive(pReceivedPackets[i],
+				pAggragatedPacketsSizes[i]);
+		// IPA HW may add padding to the packets to align to 4B
+		if (pAggragatedPacketsSizes[i] > nBytesReceived)
+		{
+			LOG_MSG_DEBUG("Receiving aggregated packet %d from the USB pipe(%d "
+					"bytes) failed!\n", i, pAggragatedPacketsSizes[i]);
+			print_buff(pReceivedPackets[i], nBytesReceived);
+			return false;
+		}
+		pAggragatedPacketsSizes[i] = nBytesReceived;
+	}
+
+
+	//comparing the received packet to the aggregated packet
+	LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		if (false == DeaggragateAndCompareOnePacket(pReceivedPackets[i],
+				pPackets[i], pPacketsSizes[i], pAggragatedPacketsSizes[i]))
+		{
+			LOG_MSG_DEBUG("Comparing aggregated packet %d failed!\n", i);
+			return false;
+		}
+	}
+
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMAggregationMultiplePacketsTest(
+		Pipe* input, Pipe* output,
+		enum ipa_ip_type m_eIP)
+{
+	//The packets that will be sent
+	Byte pPackets[MAX_PACKETS_IN_NDP + 1][MAX_PACKET_SIZE];
+	//The real sizes of the packets that will be sent
+	int pPacketsSizes[MAX_PACKETS_IN_NDP + 1];
+	//Buffer for the packet that will be received
+	Byte pReceivedPacket[2*MAX_PACKET_SIZE];
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[MAX_PACKETS_IN_NDP + 1];
+	//Total size of all sent packets (this is the max size of the aggregated packet
+	//minus the size of the header and the 2 NDPs)
+	int nTotalPacketsSize = MAX_PACKET_SIZE - (4 * (MAX_PACKETS_IN_NDP + 1)) - 24;
+
+	//initialize the packets
+	for (int i = 0; i < MAX_PACKETS_IN_NDP + 1; i++)
+	{
+		if (MAX_PACKETS_IN_NDP == i)
+			pPacketsSizes[i] = nTotalPacketsSize;
+		else
+		{
+			pPacketsSizes[i] = nTotalPacketsSize / (MAX_PACKETS_IN_NDP + 1);
+			pPacketsSizes[i] += (pPacketsSizes[i] % 4 == 0 ? 0 :
+				4 - pPacketsSizes[i] % 4);
+		}
+		nTotalPacketsSize -= pPacketsSizes[i];
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pPackets[i][size] = i;
+			size++;
+		}
+	}
+
+	//send the packets
+	for (int i = 0; i < MAX_PACKETS_IN_NDP + 1; i++)
+	{
+		LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+					pPacketsSizes[i]);
+		int nBytesSent = input->Send(pPackets[i], pPacketsSizes[i]);
+
+		if (pPacketsSizes[i] != nBytesSent)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+					"failed!\n", i, pPacketsSizes[i]);
+			return false;
+		}
+	}
+
+	//receive the aggregated packet
+	LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be "
+			"there)\n", MAX_PACKET_SIZE);
+	int nBytesReceived = output->Receive(pReceivedPacket, MAX_PACKET_SIZE);
+	if (MAX_PACKET_SIZE != nBytesReceived)
+	{
+		LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", MAX_PACKET_SIZE);
+		print_buff(pReceivedPacket, nBytesReceived);
+		return false;
+	}
+
+	//deaggregating the aggregated packet
+	return DeaggragateAndComparePackets(pReceivedPacket, pPackets,
+			pPacketsSizes, MAX_PACKETS_IN_NDP+1, nBytesReceived);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMAggregationDifferentStreamIdsTest(
+		Pipe* input, Pipe* output,
+		enum ipa_ip_type m_eIP)
+{
+	//The packets that will be sent
+	Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+	//The real sizes of the packets that will be sent
+	int pPacketsSizes[NUM_PACKETS];
+	//Buffer for the packet that will be received
+	Byte pReceivedPacket[2*MAX_PACKET_SIZE];
+	//Total size of all sent packets (this is the max size of the aggregated
+	//packet minus the size of the header and the NDPs)
+	int nTotalPacketsSize = MAX_PACKET_SIZE - (16 * NUM_PACKETS) - 12;
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[NUM_PACKETS];
+	Byte pPacketsStreamId[NUM_PACKETS];
+
+	//initialize the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		pPacketsStreamId[i] = i;
+		if (NUM_PACKETS - 1 == i)
+			pPacketsSizes[i] = nTotalPacketsSize + 12;
+		else
+			pPacketsSizes[i] = nTotalPacketsSize / NUM_PACKETS;
+		while (0 != pPacketsSizes[i] % 4)
+			pPacketsSizes[i]++;
+		nTotalPacketsSize -= pPacketsSizes[i];
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pPackets[i][size] = i;
+			size++;
+		}
+	}
+
+	nIPv4DSTAddr = ntohl(0x7F000001);
+	memcpy (&pPackets[0][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+	nIPv4DSTAddr = ntohl(0xC0A80101);
+	memcpy (&pPackets[1][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+	nIPv4DSTAddr = ntohl(0xC0A80102);
+	memcpy (&pPackets[2][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+	nIPv4DSTAddr = ntohl(0xC0A80103);
+	memcpy (&pPackets[3][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+	nIPv4DSTAddr = ntohl(0xC0A80104);
+	memcpy (&pPackets[4][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+
+	//send the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+				pPacketsSizes[i]);
+		int nBytesSent = input->Send(pPackets[i], pPacketsSizes[i]);
+		if (pPacketsSizes[i] != nBytesSent)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+					"failed!\n", i, pPacketsSizes[i]);
+			return false;
+		}
+	}
+
+	//receive the aggregated packet
+	LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be "
+			"there)\n", MAX_PACKET_SIZE + 12);
+	int nBytesReceived = output->Receive(pReceivedPacket, MAX_PACKET_SIZE + 12);
+	if (MAX_PACKET_SIZE + 12 != nBytesReceived)
+	{
+		LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", MAX_PACKET_SIZE + 12);
+		print_buff(pReceivedPacket, nBytesReceived + 12);
+		return false;
+	}
+
+	//deaggregating the aggregated packet
+	return DeaggragateAndComparePacketsWithStreamId(pReceivedPacket, pPackets,
+			pPacketsSizes, NUM_PACKETS, nBytesReceived, pPacketsStreamId);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::MBIMAggregationNoInterleavingStreamIdsTest(
+		Pipe* input, Pipe* output,
+		enum ipa_ip_type m_eIP)
+{
+	//The packets that will be sent
+	Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+	//The real sizes of the packets that will be sent
+	int pPacketsSizes[NUM_PACKETS];
+	//Buffer for the packet that will be received
+	Byte pReceivedPacket[2*MAX_PACKET_SIZE];
+	//Total size of all sent packets (this is the max size of the aggregated packet
+	//minus the size of the header and the NDPs)
+	int nTotalPacketsSize = MAX_PACKET_SIZE - (16 * NUM_PACKETS) - 12;
+	uint32_t nIPv4DSTAddr;
+	size_t pIpPacketsSizes[NUM_PACKETS];
+	Byte pPacketsStreamId[NUM_PACKETS];
+
+	//initialize the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		pPacketsStreamId[i] = i % 2;
+		if (NUM_PACKETS - 1 == i)
+			pPacketsSizes[i] = nTotalPacketsSize + 12;
+		else
+			pPacketsSizes[i] = nTotalPacketsSize / NUM_PACKETS;
+		while (0 != pPacketsSizes[i] % 4)
+			pPacketsSizes[i]++;
+		nTotalPacketsSize -= pPacketsSizes[i];
+
+		// Load input data (IP packet) from file
+		pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		int size = pIpPacketsSizes[i];
+		while (size < pPacketsSizes[i])
+		{
+			pPackets[i][size] = i;
+			size++;
+		}
+	}
+
+	nIPv4DSTAddr = ntohl(0x7F000001);
+	memcpy (&pPackets[0][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+	nIPv4DSTAddr = ntohl(0xC0A80101);
+	memcpy (&pPackets[1][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+	nIPv4DSTAddr = ntohl(0x7F000001);
+	memcpy (&pPackets[2][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+	nIPv4DSTAddr = ntohl(0xC0A80101);
+	memcpy (&pPackets[3][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+	nIPv4DSTAddr = ntohl(0x7F000001);
+	memcpy (&pPackets[4][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+
+	//send the packets
+	for (int i = 0; i < NUM_PACKETS; i++)
+	{
+		LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+				pPacketsSizes[i]);
+		int nBytesSent = input->Send(pPackets[i], pPacketsSizes[i]);
+		if (pPacketsSizes[i] != nBytesSent)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+					"failed!\n", i, pPacketsSizes[i]);
+			return false;
+		}
+	}
+
+	//receive the aggregated packet
+	LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be "
+			"there)\n", MAX_PACKET_SIZE + 12);
+	int nBytesReceived = output->Receive(pReceivedPacket,
+			MAX_PACKET_SIZE + 12);
+	if (MAX_PACKET_SIZE + 12 != nBytesReceived)
+	{
+		LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d bytes)"
+				" failed!\n", MAX_PACKET_SIZE + 12);
+		print_buff(pReceivedPacket, nBytesReceived + 12);
+		return false;
+	}
+
+	//deaggregating the aggregated packet
+	return DeaggragateAndComparePacketsWithStreamId(pReceivedPacket, pPackets,
+			pPacketsSizes, NUM_PACKETS, nBytesReceived, pPacketsStreamId);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::DeaggragateAndComparePackets(
+		Byte pAggregatedPacket[MAX_PACKET_SIZE],
+		Byte pExpectedPackets[MAX_PACKETS_IN_MBIM_TESTS][MAX_PACKET_SIZE],
+		int pPacketsSizes[MAX_PACKETS_IN_MBIM_TESTS], int nNumPackets, int nAggregatedPacketSize)
+{
+	int nPacketNum = 0;
+	int i = 0;
+	int nNdpStart = 0;
+	Byte pNdpIndex[2] = {0};
+	Byte pNdpLen[2] = {0};
+	if (0x4e != pAggregatedPacket[i] || 0x43 != pAggregatedPacket[i+1] ||
+			0x4d != pAggregatedPacket[i+2]|| 0x48 != pAggregatedPacket[i+3])
+	{
+		LOG_MSG_DEBUG("Error: Wrong NTH16 signature: 0x%02x 0x%02x 0x%02x "
+				"0x%02x(should be 0x4e, 0x43, 0x4d, 0x48)\n",
+				pAggregatedPacket[i], pAggregatedPacket[i+1],
+				pAggregatedPacket[i+2], pAggregatedPacket[i+3]);
+		return false;
+	}
+	i += 4;
+	if (0x0c != pAggregatedPacket[i] || 0x00 != pAggregatedPacket[i+1])
+	{
+		LOG_MSG_DEBUG("Error: Wrong header length: 0x%02x 0x%02x(should be 0x0c, "
+				"0x00)\n",
+				pAggregatedPacket[i], pAggregatedPacket[i+1]);
+		return false;
+	}
+	i += 4;  //ignoring sequence number
+	if ((nAggregatedPacketSize & 0x00FF) != pAggregatedPacket[i] ||
+			(nAggregatedPacketSize >> 8) != pAggregatedPacket[i+1])
+	{
+		LOG_MSG_DEBUG("Error: Wrong aggregated packet length: 0x%02x 0x%02x"
+				"(should be 0x%02x, 0x%02x)\n",
+				pAggregatedPacket[i], pAggregatedPacket[i+1],
+				nAggregatedPacketSize & 0x00FF, nAggregatedPacketSize >> 8);
+		return false;
+	}
+	i += 2;
+	pNdpIndex[0] = pAggregatedPacket[i];  //least significant byte
+	pNdpIndex[1] = pAggregatedPacket[i+1];  //most significant byte
+	//reading the NDP
+	while (0x00 != pNdpIndex[0] || 0x00 != pNdpIndex[1])
+	{
+		i = pNdpIndex[0] + 256*pNdpIndex[1];  //NDP should begin here
+		nNdpStart = i;
+
+		if (0x49 != pAggregatedPacket[i] || 0x50 != pAggregatedPacket[i + 1] ||
+			0x53 != pAggregatedPacket[i + 2] || 0x00 != pAggregatedPacket[i + 3])
+		{
+			LOG_MSG_DEBUG("Error: Wrong NDP16 signature: 0x%02x 0x%02x "
+				"0x%02x 0x%02x(should be 0x49, 0x50, 0x53, 0x00)\n",
+				pAggregatedPacket[i], pAggregatedPacket[i + 1],
+				pAggregatedPacket[i + 2], pAggregatedPacket[i + 3]);
+			return false;
+		}
+		i += 4;
+		pNdpLen[0] = pAggregatedPacket[i];  //least significant byte
+		pNdpLen[1] = pAggregatedPacket[i+1];  //most significant byte
+		if (0x00 != pAggregatedPacket[nNdpStart + pNdpLen[0] + 256*pNdpLen[1] - 2] ||
+				0x00 != pAggregatedPacket[nNdpStart + pNdpLen[0] + 256*pNdpLen[1] -1])
+		{
+			LOG_MSG_DEBUG("Error: Wrong end of NDP: 0x%02x 0x%02x(should be 0x00,"
+					" 0x00)\n",
+					pAggregatedPacket[nNdpStart + pNdpLen[0] + 256*pNdpLen[1] - 2],
+					pAggregatedPacket[nNdpStart + pNdpLen[0] + 256*pNdpLen[1] - 1]);
+			return false;
+		}
+		i += 2;
+		pNdpIndex[0] = pAggregatedPacket[i];  //least significant byte
+		pNdpIndex[1] = pAggregatedPacket[i+1];  //most significant byte
+		i += 2;
+		while (i <= nNdpStart + pNdpLen[0] + 256*pNdpLen[1] - 2)
+		{ //going over all the datagrams in this NDP
+			Byte pDatagramIndex[2] = {0};
+			Byte pDatagramLen[2] = {0};
+			int packetIndex = 0;
+			pDatagramIndex[0] = pAggregatedPacket[i];  //least significant byte
+			pDatagramIndex[1] = pAggregatedPacket[i+1];  //most significant byte
+			i += 2;
+			if (0x00 == pDatagramIndex[0] && 0x00 == pDatagramIndex[1])
+				break;  //zero padding after all datagrams
+			if (nPacketNum >= nNumPackets)
+			{
+				LOG_MSG_DEBUG("Error: wrong number of packets: %d(should be %d)\n",
+						nPacketNum, nNumPackets);
+				return false;
+			}
+			pDatagramLen[0] = pAggregatedPacket[i];  //least significant byte
+			pDatagramLen[1] = pAggregatedPacket[i+1];  //most significant byte
+			i += 2;
+			packetIndex = pDatagramIndex[0] + 256*pDatagramIndex[1];
+			if (pDatagramLen[0] + 256*pDatagramLen[1] != pPacketsSizes[nPacketNum])
+			{
+				LOG_MSG_DEBUG("Error: Wrong packet %d length: 0x%02x 0x%02x"
+						"(should be %d)\n", nPacketNum, pDatagramLen[0],
+						pDatagramLen[1], pPacketsSizes[nPacketNum]);
+				return false;
+			}
+			if (0 != memcmp(pExpectedPackets[nPacketNum],
+					&pAggregatedPacket[packetIndex], pPacketsSizes[nPacketNum]))
+			{
+				LOG_MSG_DEBUG("Error: Comparison of packet %d failed!\n",
+						nPacketNum);
+
+				return false;
+			}
+			nPacketNum++;
+		}
+	}
+
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+void MBIMAggregationScenarios::AggregatePackets(
+		Byte pAggregatedPacket[MAX_PACKET_SIZE]/*ouput*/,
+		Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE],
+		int pPacketsSizes[NUM_PACKETS], int nNumPackets,
+		int nAggregatedPacketSize)
+{
+	int i = 0;
+	int pDatagramIndexes[NUM_PACKETS] = {0};
+	int nNdpIndex = 0;
+	int nNdpLen = 0;
+	//NTH16 signature
+	pAggregatedPacket[i] = 0x4e;
+	pAggregatedPacket[i+1] = 0x43;
+	pAggregatedPacket[i+2] = 0x4d;
+	pAggregatedPacket[i+3] = 0x48;
+	i += 4;
+	//header length
+	pAggregatedPacket[i] = 0x0c;
+	pAggregatedPacket[i+1] = 0x00;
+	i += 2;
+	//sequence number
+	pAggregatedPacket[i] = 0x00;
+	pAggregatedPacket[i+1] = 0x00;
+	i += 2;
+	//aggregated packet length
+	pAggregatedPacket[i] = nAggregatedPacketSize & 0x00FF;
+	pAggregatedPacket[i+1] = nAggregatedPacketSize >> 8;
+	i += 2;
+	//NDP index
+	for (int j = 0; j < nNumPackets; j++)
+		nNdpIndex += pPacketsSizes[j];
+	nNdpIndex += i + 2;
+	while (0 != nNdpIndex % 4)
+		nNdpIndex++;
+	pAggregatedPacket[i] = nNdpIndex & 0x00FF;
+	pAggregatedPacket[i+1] = nNdpIndex >> 8;
+	i += 2;
+	//packets
+	for (int j = 0; j < nNumPackets; j++)
+	{
+		pDatagramIndexes[j] = i;
+		for (int k = 0; k < pPacketsSizes[j]; k++)
+		{
+			pAggregatedPacket[i] = pPackets[j][k];
+			i++;
+		}
+	}
+	while (i < nNdpIndex)
+	{
+		pAggregatedPacket[i] = 0x00;
+		i++;
+	}
+
+	//NDP16 signature
+	pAggregatedPacket[i] = 0x49;
+	pAggregatedPacket[i+1] = 0x50;
+	pAggregatedPacket[i+2] = 0x53;
+	pAggregatedPacket[i+3] = 0x00;
+	i += 4;
+	//NDP length
+	nNdpLen = 4*nNumPackets + 8 + 2;
+	while (nNdpLen % 4 != 0)
+		nNdpLen += 2;
+	pAggregatedPacket[i] = nNdpLen & 0x00FF;
+	pAggregatedPacket[i+1] = nNdpLen >> 8;
+	i += 2;
+	//next NDP
+	pAggregatedPacket[i] = 0x00;
+	pAggregatedPacket[i+1] = 0x00;
+	i += 2;
+	for (int j = 0; j < nNumPackets; j++)
+	{
+		//datagram index
+		pAggregatedPacket[i] = pDatagramIndexes[j] & 0x00FF;
+		pAggregatedPacket[i+1] = pDatagramIndexes[j] >> 8;
+		i += 2;
+		//datagram length
+		pAggregatedPacket[i] = pPacketsSizes[j] & 0x00FF;
+		pAggregatedPacket[i+1] = pPacketsSizes[j] >> 8;
+		i += 2;
+	}
+	//zeros in the end of NDP
+	while (i < nAggregatedPacketSize)
+	{
+		pAggregatedPacket[i] = 0x00;
+		i++;
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+void MBIMAggregationScenarios::AggregatePacketsWithStreamId(
+		Byte pAggregatedPacket[MAX_PACKET_SIZE]/*ouput*/,
+		Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE],
+		int pPacketsSizes[NUM_PACKETS], int nNumPackets, int nAggregatedPacketSize,
+		Byte pPacketsStreamId[NUM_PACKETS])
+{
+	int i = 0;
+	int n = 0;
+	int pDatagramIndexes[NUM_PACKETS] = {0};
+	int nNdpIndex[NUM_PACKETS] = {0};
+	int nNdpLen = 0;
+	Byte currStreamId = pPacketsStreamId[0];
+	int nNdpFirstPacket[NUM_PACKETS] = {0};
+	int nNdpAfterLastPacket[NUM_PACKETS] = {0};
+	int nNumNDPs = 0;
+	for (n = 0; n < nNumPackets; n++)
+	{
+		if (currStreamId != pPacketsStreamId[n])
+		{
+			nNdpAfterLastPacket[nNumNDPs] = n;
+			nNumNDPs++;
+			nNdpFirstPacket[nNumNDPs] = n;
+			currStreamId = pPacketsStreamId[n];
+		}
+	}
+	nNdpAfterLastPacket[nNumNDPs] = n;
+	nNumNDPs++;
+	//calculate NDP indexes
+	nNdpIndex[0] += 12;  //adding the header
+	for (int j = 0; j < nNumNDPs; j++)
+	{
+		for (n = nNdpFirstPacket[j]; n < nNdpAfterLastPacket[j]; n++)
+			nNdpIndex[j] += pPacketsSizes[n];  //adding the packets
+		while (0 != nNdpIndex[j] % 4)
+			nNdpIndex[j]++;
+		if (j < nNumNDPs - 1)
+			nNdpIndex[j+1] += nNdpIndex[j] + 12 + 4*(nNdpAfterLastPacket[j] -
+					nNdpFirstPacket[j]);  //adding the location after the current NDP to the next NDP
+	}
+	//start building the aggregated packet
+	//NTH16 signature
+	pAggregatedPacket[i] = 0x4e;
+	pAggregatedPacket[i+1] = 0x43;
+	pAggregatedPacket[i+2] = 0x4d;
+	pAggregatedPacket[i+3] = 0x48;
+	i += 4;
+	//header length
+	pAggregatedPacket[i] = 0x0c;
+	pAggregatedPacket[i+1] = 0x00;
+	i += 2;
+	//sequence number
+	pAggregatedPacket[i] = 0x00;
+	pAggregatedPacket[i+1] = 0x00;
+	i += 2;
+	//aggregated packet length
+	pAggregatedPacket[i] = nAggregatedPacketSize & 0x00FF;
+	pAggregatedPacket[i+1] = nAggregatedPacketSize >> 8;;
+	i += 2;
+	//first NDP index
+	pAggregatedPacket[i] = nNdpIndex[0] & 0x00FF;
+	pAggregatedPacket[i+1] = nNdpIndex[0] >> 8;
+	i += 2;
+	for (n = 0; n < nNumNDPs; n++)
+	{
+		//packets
+		for (int j = nNdpFirstPacket[n]; j < nNdpAfterLastPacket[n]; j++)
+		{
+			pDatagramIndexes[j] = i;
+			for (int k = 0; k < pPacketsSizes[j]; k++)
+			{
+				pAggregatedPacket[i] = pPackets[j][k];
+				i++;
+			}
+		}
+		while (i < nNdpIndex[n])
+		{
+			pAggregatedPacket[i] = 0x00;
+			i++;
+		}
+		//NDP signature
+		pAggregatedPacket[i] = 0x49;
+		pAggregatedPacket[i+1] = 0x50;
+		pAggregatedPacket[i+2] = 0x53;
+		pAggregatedPacket[i+3] = pPacketsStreamId[nNdpFirstPacket[n]];
+		i += 4;
+		//NDP length
+		nNdpLen = 4*(nNdpAfterLastPacket[n] - nNdpFirstPacket[n]) + 8 + 2;
+		while (nNdpLen % 4 != 0)
+			nNdpLen += 2;
+		pAggregatedPacket[i] = nNdpLen & 0x00FF;
+		pAggregatedPacket[i+1] = nNdpLen >> 8;
+		i += 2;
+		//next NDP
+		pAggregatedPacket[i] = nNdpIndex[n+1] & 0x00FF;
+		pAggregatedPacket[i+1] = nNdpIndex[n+1] >> 8;
+		i += 2;
+		for (int j = nNdpFirstPacket[n]; j < nNdpAfterLastPacket[n]; j++)
+		{
+			//datagram index
+			pAggregatedPacket[i] = pDatagramIndexes[j] & 0x00FF;
+			pAggregatedPacket[i+1] = pDatagramIndexes[j] >> 8;
+			i += 2;
+			//datagram length
+			pAggregatedPacket[i] = pPacketsSizes[j] & 0x00FF;
+			pAggregatedPacket[i+1] = pPacketsSizes[j] >> 8;
+			i += 2;
+		}
+		//zeros in the end of NDP
+		while (i < nNdpIndex[n] + nNdpLen)
+		{
+			pAggregatedPacket[i] = 0x00;
+			i++;
+		}
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::DeaggragateAndCompareOnePacket(
+		Byte pAggregatedPacket[MAX_PACKET_SIZE],
+		Byte pExpectedPacket[MAX_PACKET_SIZE], int nPacketsSize,
+		int nAggregatedPacketSize)
+{
+	int nPacketNum = 0;
+	int i = 0;
+	int nNdpStart = 0;
+	Byte pNdpIndex[2] = {0};
+	Byte pNdpLen[2] = {0};
+	if (0x4e != pAggregatedPacket[i] || 0x43 != pAggregatedPacket[i+1] ||
+			0x4d != pAggregatedPacket[i+2]|| 0x48 != pAggregatedPacket[i+3])
+	{
+		LOG_MSG_DEBUG("Error: Wrong NTH16 signature: 0x%02x 0x%02x 0x%02x "
+				"0x%02x(should be 0x4e, 0x43, 0x4d, 0x48)\n",
+				pAggregatedPacket[i], pAggregatedPacket[i+1],
+				pAggregatedPacket[i+2], pAggregatedPacket[i+3]);
+		return false;
+	}
+	i += 4;
+	if (0x0c != pAggregatedPacket[i] || 0x00 != pAggregatedPacket[i+1])
+	{
+		LOG_MSG_DEBUG("Error: Wrong header length: 0x%02x 0x%02x(should be 0x0c,"
+				" 0x00)\n", pAggregatedPacket[i], pAggregatedPacket[i+1]);
+		return false;
+	}
+	i += 4;  //ignoring sequence number
+	if ((nAggregatedPacketSize & 0x00FF) != pAggregatedPacket[i] ||
+			(nAggregatedPacketSize >> 8) != pAggregatedPacket[i+1])
+	{
+		LOG_MSG_DEBUG("Error: Wrong aggregated packet length: 0x%02x 0x%02x"
+				"(should be 0x%02x, 0x%02x)\n",
+				pAggregatedPacket[i], pAggregatedPacket[i+1],
+				nAggregatedPacketSize & 0x00FF, nAggregatedPacketSize >> 8);
+		return false;
+	}
+	i += 2;
+	pNdpIndex[0] = pAggregatedPacket[i];  //least significant byte
+	pNdpIndex[1] = pAggregatedPacket[i+1];  //most significant byte
+	//reading the NDP
+	while (0x00 != pNdpIndex[0] || 0x00 != pNdpIndex[1])
+	{
+		i = pNdpIndex[0] + 256*pNdpIndex[1];  //NDP should begin here
+		nNdpStart = i;
+
+		if (0x49 != pAggregatedPacket[i] || 0x50 != pAggregatedPacket[i+1] ||
+				0x53 != pAggregatedPacket[i+2] || 0x00 != pAggregatedPacket[i+3])
+		{
+			LOG_MSG_DEBUG("Error: Wrong NDP16 signature: 0x%02x 0x%02x "
+					"0x%02x 0x%02x(should be 0x49, 0x50, 0x53, 0x00)\n",
+					pAggregatedPacket[i], pAggregatedPacket[i+1],
+					pAggregatedPacket[i+2], pAggregatedPacket[i+3]);
+			return false;
+		}
+		i += 4;
+		pNdpLen[0] = pAggregatedPacket[i];  //least significant byte
+		pNdpLen[1] = pAggregatedPacket[i+1];  //most significant byte
+		if (0x00 != pAggregatedPacket[nNdpStart + pNdpLen[0] + 256*pNdpLen[1] - 2] ||
+				0x00 != pAggregatedPacket[nNdpStart + pNdpLen[0] + 256*pNdpLen[1] -1])
+		{
+			LOG_MSG_DEBUG("Error: Wrong end of NDP: 0x%02x 0x%02x(should be "
+					"0x00, 0x00)\n",
+					pAggregatedPacket[nNdpStart + pNdpLen[0] + 256*pNdpLen[1] - 2],
+					pAggregatedPacket[nNdpStart + pNdpLen[0] + 256*pNdpLen[1] - 1]);
+			return false;
+		}
+		i += 2;
+		pNdpIndex[0] = pAggregatedPacket[i];  //least significant byte
+		pNdpIndex[1] = pAggregatedPacket[i+1];  //most significant byte
+		i += 2;
+		while (i <= nNdpStart + pNdpLen[0] + 256*pNdpLen[1] - 2)
+		{ //going over all the datagrams in this NDP
+			Byte pDatagramIndex[2] = {0};
+			Byte pDatagramLen[2] = {0};
+			int packetIndex = 0;
+			pDatagramIndex[0] = pAggregatedPacket[i];  //least significant byte
+			pDatagramIndex[1] = pAggregatedPacket[i+1];  //most significant byte
+			i += 2;
+			if (0x00 == pDatagramIndex[0] && 0x00 == pDatagramIndex[1])
+				break;  //zero padding after all datagrams
+			if (nPacketNum > 1)
+			{
+				LOG_MSG_DEBUG("Error: wrong number of packets: %d(should be %d)\n",
+						nPacketNum, 1);
+				return false;
+			}
+			pDatagramLen[0] = pAggregatedPacket[i];  //least significant byte
+			pDatagramLen[1] = pAggregatedPacket[i+1];  //most significant byte
+			i += 2;
+			packetIndex = pDatagramIndex[0] + 256*pDatagramIndex[1];
+			if (pDatagramLen[0] + 256*pDatagramLen[1] != nPacketsSize)
+			{
+				LOG_MSG_DEBUG("Error: Wrong packet %d length: 0x%02x 0x%02x"
+						"(should be %d)\n", nPacketNum, pDatagramLen[0],
+						pDatagramLen[1], nPacketsSize);
+				return false;
+			}
+			if (0 != memcmp(pExpectedPacket, &pAggregatedPacket[packetIndex],
+					nPacketsSize))
+			{
+				LOG_MSG_DEBUG("Error: Comparison of packet %d failed!\n",
+						nPacketNum);
+				return false;
+			}
+			nPacketNum++;
+		}
+	}
+
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool MBIMAggregationScenarios::DeaggragateAndComparePacketsWithStreamId(
+		Byte pAggregatedPacket[MAX_PACKET_SIZE],
+		Byte pExpectedPackets[][MAX_PACKET_SIZE], int pPacketsSizes[],
+		int nNumPackets, int nAggregatedPacketSize,
+		Byte pPacketsStreamId[NUM_PACKETS])
+{
+	int nPacketNum = 0;
+	int i = 0;
+	int nNdpStart = 0;
+	Byte pNdpIndex[2] = {0};
+	Byte pNdpLen[2] = {0};
+	if (0x4e != pAggregatedPacket[i] || 0x43 != pAggregatedPacket[i+1] ||
+			0x4d != pAggregatedPacket[i+2]|| 0x48 != pAggregatedPacket[i+3])
+	{
+		LOG_MSG_DEBUG("Error: Wrong NTH16 signature: 0x%02x 0x%02x 0x%02x "
+				"0x%02x(should be 0x4e, 0x43, 0x4d, 0x48)\n",
+				pAggregatedPacket[i], pAggregatedPacket[i+1],
+				pAggregatedPacket[i+2], pAggregatedPacket[i+3]);
+		return false;
+	}
+	i += 4;
+	if (0x0c != pAggregatedPacket[i] || 0x00 != pAggregatedPacket[i+1])
+	{
+		LOG_MSG_DEBUG("Error: Wrong header length: 0x%02x 0x%02x(should be "
+				"0x0c, 0x00)\n",pAggregatedPacket[i], pAggregatedPacket[i+1]);
+		return false;
+	}
+	i += 4;  //ignoring sequence number
+	if ((nAggregatedPacketSize & 0x00FF) != pAggregatedPacket[i] ||
+			(nAggregatedPacketSize >> 8) != pAggregatedPacket[i+1])
+	{
+		LOG_MSG_DEBUG("Error: Wrong aggregated packet length: 0x%02x 0x%02x"
+				"(should be 0x%02x, 0x%02x)\n", pAggregatedPacket[i],
+				pAggregatedPacket[i+1], nAggregatedPacketSize & 0x00FF,
+				nAggregatedPacketSize >> 8);
+		return false;
+	}
+	i += 2;
+	pNdpIndex[0] = pAggregatedPacket[i];  //least significant byte
+	pNdpIndex[1] = pAggregatedPacket[i+1];  //most significant byte
+	//reading the NDP
+	while (0x00 != pNdpIndex[0] || 0x00 != pNdpIndex[1])
+	{
+		i = pNdpIndex[0] + 256*pNdpIndex[1];  //NDP should begin here
+		nNdpStart = i;
+		if (0x49 != pAggregatedPacket[i] || 0x50 != pAggregatedPacket[i+1] ||
+				0x53 != pAggregatedPacket[i+2])
+		{
+			LOG_MSG_DEBUG("Error: Wrong NDP16 signature: 0x%02x 0x%02x 0x%02x"
+					"(should be 0x49, 0x50, 0x53)\n", pAggregatedPacket[i],
+					pAggregatedPacket[i+1], pAggregatedPacket[i+2]);
+			return false;
+		}
+		if (pPacketsStreamId[nPacketNum] != pAggregatedPacket[i+3])
+		{
+			LOG_MSG_DEBUG("Error: Wrong NDP stream id: 0x%02x(should be 0x%02x)\n",
+					pAggregatedPacket[i+3], pPacketsStreamId[nPacketNum]);
+			return false;
+		}
+		i += 4;
+		pNdpLen[0] = pAggregatedPacket[i];  //least significant byte
+		pNdpLen[1] = pAggregatedPacket[i+1];  //most significant byte
+		if (0x00 != pAggregatedPacket[nNdpStart + pNdpLen[0] + 256*pNdpLen[1] - 2] ||
+				0x00 != pAggregatedPacket[nNdpStart + pNdpLen[0] + 256*pNdpLen[1] -1])
+		{
+			LOG_MSG_DEBUG("Error: Wrong end of NDP: 0x%02x 0x%02x(should be 0x00, "
+					"0x00)\n",
+					pAggregatedPacket[nNdpStart + pNdpLen[0] + 256*pNdpLen[1] - 2],
+					pAggregatedPacket[nNdpStart + pNdpLen[0] + 256*pNdpLen[1] - 1]);
+			return false;
+		}
+		i += 2;
+		pNdpIndex[0] = pAggregatedPacket[i];  //least significant byte
+		pNdpIndex[1] = pAggregatedPacket[i+1];  //most significant byte
+		i += 2;
+		while (i <= nNdpStart + pNdpLen[0] + 256*pNdpLen[1] - 2)
+		{ //going over all the datagrams in this NDP
+			Byte pDatagramIndex[2] = {0};
+			Byte pDatagramLen[2] = {0};
+			int packetIndex = 0;
+			pDatagramIndex[0] = pAggregatedPacket[i];  //least significant byte
+			pDatagramIndex[1] = pAggregatedPacket[i+1];  //most significant byte
+			i += 2;
+			if (0x00 == pDatagramIndex[0] && 0x00 == pDatagramIndex[1])
+				break;  //zero padding after all datagrams
+			if (nPacketNum >= nNumPackets)
+			{
+				LOG_MSG_DEBUG("Error: wrong number of packets: %d(should be %d)\n",
+						nPacketNum, nNumPackets);
+				return false;
+			}
+			pDatagramLen[0] = pAggregatedPacket[i];  //least significant byte
+			pDatagramLen[1] = pAggregatedPacket[i+1];  //most significant byte
+			i += 2;
+			packetIndex = pDatagramIndex[0] + 256*pDatagramIndex[1];
+			if (pDatagramLen[0] + 256*pDatagramLen[1] != (int)pPacketsSizes[nPacketNum])
+			{
+				LOG_MSG_DEBUG("Error: Wrong packet %d length: 0x%02x 0x%02x"
+						"(should be %d)\n", nPacketNum, pDatagramLen[0],
+						pDatagramLen[1], pPacketsSizes[nPacketNum]);
+				return false;
+			}
+			if (0 != memcmp(pExpectedPackets[nPacketNum],
+					&pAggregatedPacket[packetIndex], pPacketsSizes[nPacketNum]))
+			{
+				LOG_MSG_DEBUG("Error: Comparison of packet %d failed!\n",
+						nPacketNum);
+				return false;
+			}
+			nPacketNum++;
+		}
+	}
+
+	return true;
+}
+
+
+class MBIMAggregationTest: public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMAggregationTest(bool generic_agg) :
+		MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMAggregationTest";
+		else
+			m_name = "MBIMAggregationTest";
+		m_description = "MBIM Aggregation test - sends 5 packets and receives 1 "
+				"aggregated packet";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRules1HeaderAggregation();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMAggregationTest(&m_UsbToIpaPipe,
+				&m_IpaToUsbPipeAgg, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class MBIMDeaggregationTest: public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMDeaggregationTest(bool generic_agg) :
+		MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMDeaggregationTest";
+		else
+			m_name = "MBIMDeaggregationTest";
+		m_description = "MBIM Deaggregation test - sends an aggregated packet made from"
+				"5 packets and receives 5 packets";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRulesDeaggregation();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMDeaggregationTest(&m_UsbToIpaPipeDeagg, &m_IpaToUsbPipe, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+class MBIMDeaggregationOnePacketTest: public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMDeaggregationOnePacketTest(bool generic_agg) :
+		MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMDeaggregationOnePacketTest";
+		else
+			m_name = "MBIMDeaggregationOnePacketTest";
+		m_description = "MBIM Deaggregation one packet test - sends an aggregated packet made"
+				"of 1 packet and receives 1 packet";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRulesDeaggregation();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMDeaggregationOnePacketTest(&m_UsbToIpaPipeDeagg, &m_IpaToUsbPipe, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+
+class MBIMDeaggregationAndAggregationTest: public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMDeaggregationAndAggregationTest(bool generic_agg)
+		: MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMDeaggregationAndAggregationTest";
+		else
+			m_name = "MBIMDeaggregationAndAggregationTest";
+		m_description = "MBIM Deaggregation and Aggregation test - sends an aggregated "
+				"packet made from 5 packets and receives the same aggregated packet";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRules1HeaderAggregation();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMDeaggregationAndAggregationTest(
+				&m_UsbToIpaPipeDeagg, &m_IpaToUsbPipeAgg, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+
+class MBIMMultipleDeaggregationAndAggregationTest:
+	public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMMultipleDeaggregationAndAggregationTest(bool generic_agg) :
+		MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMMultipleDeaggregationAndAggregationTest";
+		else
+			m_name = "MBIMMultipleDeaggregationAndAggregationTest";
+		m_description = "MBIM Multiple Deaggregation and Aggregation test - sends 5 aggregated "
+				"packets each one made of 1 packet and receives an aggregated packet made of the"
+				"5 packets";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRules1HeaderAggregation();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMMultipleDeaggregationAndAggregationTest(
+				&m_UsbToIpaPipeDeagg, &m_IpaToUsbPipeAgg, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class MBIMAggregationLoopTest: public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMAggregationLoopTest(bool generic_agg)
+		: MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMggregationLoopTest";
+		else
+			m_name = "MBIMggregationLoopTest";
+		m_description = "MBIM Aggregation Loop test - sends 5 packets and expects to"
+				"receives 1 aggregated packet a few times";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRules1HeaderAggregation();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMAggregationLoopTest(
+				&m_UsbToIpaPipe, &m_IpaToUsbPipeAgg, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class MBIMAggregationTimeLimitTest: public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMAggregationTimeLimitTest(bool generic_agg)
+		: MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMAggregationTimeLimitTest";
+		else
+			m_name = "MBIMAggregationTimeLimitTest";
+		m_description = "MBIM Aggregation time limit test - sends 1 small packet "
+				"smaller than the byte limit and receives 1 aggregated packet";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRules1HeaderAggregationTime();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMAggregationTimeLimitTest(
+				&m_UsbToIpaPipe, &m_IpaToUsbPipeAggTime, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class MBIMAggregationByteLimitTest: public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMAggregationByteLimitTest(bool generic_agg)
+		: MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMAggregationByteLimitTest";
+		else
+			m_name = "MBIMAggregationByteLimitTest";
+		m_description = "MBIM Aggregation byte limit test - sends 2 packets that together "
+				"are larger than the byte limit ";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRules1HeaderAggregation();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMAggregationByteLimitTest(
+				&m_UsbToIpaPipe, &m_IpaToUsbPipeAgg, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class MBIMAggregationByteLimitTestFC: public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMAggregationByteLimitTestFC(bool generic_agg)
+		: MBIMAggregationTestFixtureConf11(generic_agg) {
+		if (generic_agg)
+			m_name = "GenMBIMAggregationByteLimitTestFC";
+		else
+			m_name = "MBIMAggregationByteLimitTestFC";
+		m_description = "MBIMAggregationByteLimitTestFC - Send 4 IP packet with FC"
+			"and expect 4 aggregated MBIM packets.";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules() {
+		return AddRules1HeaderAggregation(true);
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMAggregationByteLimitTestFC(
+				&m_UsbToIpaPipe, &m_IpaToUsbPipeAgg, m_eIP);
+	}
+};
+
+class MBIMAggregationDualDpTestFC : public MBIMAggregationTestFixtureConf11
+{
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMAggregationDualDpTestFC(bool generic_agg)
+		: MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg) m_name = "GenMBIMAggregationDualDpTestFC";
+		else m_name = "MBIMAggregationDualDpTestFC";
+		m_description = "MBIMAggregationDualDpTestFC - Send IP packets "
+			"on two datapathes: one with FC and one without. "
+			"Expect 2 aggregated MBIM packets on pipe with FC. "
+			"Expect one aggregated MBIM packet on pipe without FC. ";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRulesAggDualFC(&m_UsbToIpaPipe,
+					 &m_IpaToUsbPipeAggTime,
+					 &m_IpaToUsbPipeAgg);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMAggregationDualDpTestFC(
+			&m_UsbToIpaPipe, &m_IpaToUsbPipeAggTime, &m_IpaToUsbPipeAgg, m_eIP);
+	}
+};
+
+class MBIMAggregationDualDpTestFcRoutingBased : public MBIMAggregationTestFixtureConf11
+{
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMAggregationDualDpTestFcRoutingBased(bool generic_agg)
+		: MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg) m_name = "GenMBIMAggregationDualDpTestFcRoutingBased";
+		else m_name = "MBIMAggregationDualDpTestFcRoutingBased";
+		m_description = "MBIMAggregationDualDpTestFcRoutingBased - Send IP packets "
+			"on two datapathes: one with RT based FC and one without. "
+			"Expect 2 aggregated MBIM packets on pipe with RT based FC. "
+			"Expect one aggregated MBIM packet on pipe without RT based FC. ";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRulesAggDualFcRoutingBased(&m_UsbToIpaPipe,
+					 &m_IpaToUsbPipeAggTime,
+					 &m_IpaToUsbPipeAgg);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMAggregationDualDpTestFC(
+			&m_UsbToIpaPipe, &m_IpaToUsbPipeAggTime, &m_IpaToUsbPipeAgg, m_eIP);
+	}
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class MBIMDeaggregationMultipleNDPTest: public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMDeaggregationMultipleNDPTest(bool generic_agg)
+		: MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMDeaggregationMultipleNDPTest";
+		else
+			m_name = "MBIMDeaggregationMultipleNDPTest";
+		m_description = "MBIM Deaggregation multiple NDP test - sends an aggregated"
+				"packet made from 5 packets and 2 NDPs and receives 5 packets";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRulesDeaggregation();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMDeaggregationMultipleNDPTest(
+				&m_UsbToIpaPipeDeagg, &m_IpaToUsbPipe, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class MBIMAggregation2PipesTest: public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMAggregation2PipesTest(bool generic_agg)
+		: MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMAggregation2PipesTest";
+		else
+			m_name = "MBIMAggregation2PipesTest";
+		m_description = "MBIM Aggregation 2 pipes test - sends 3 packets from one pipe"
+				"and an aggregated packet made of 2 packets from another pipe and "
+				"receives 1 aggregated packet made of all 5 packets";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRules1HeaderAggregation();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMAggregation2PipesTest(
+				&m_UsbToIpaPipeDeagg, &m_UsbToIpaPipe, &m_IpaToUsbPipeAgg, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class MBIMAggregationTimeLimitLoopTest: public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMAggregationTimeLimitLoopTest(bool generic_agg)
+		: MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMAggregationTimeLimitLoopTest";
+		else
+			m_name = "MBIMAggregationTimeLimitLoopTest";
+		m_description = "MBIM Aggregation time limit loop test - sends 5 small packet "
+				"smaller than the byte limit and receives 5 aggregated packet";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRules1HeaderAggregationTime();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMAggregationTimeLimitLoopTest(
+				&m_UsbToIpaPipe, &m_IpaToUsbPipeAggTime, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class MBIMAggregationMultiplePacketsTest: public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMAggregationMultiplePacketsTest(bool generic_agg)
+		: MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMAggregationMultiplePacketsTest";
+		else
+			m_name = "MBIMAggregationMultiplePacketsTest";
+		m_description = "MBIM Aggregation multiple packets test - sends 9 packets "
+				"with same stream ID and receives 1 aggregated packet with 2 NDPs";
+		this->m_runInRegression = false;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRules1HeaderAggregation();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMAggregationMultiplePacketsTest(
+				&m_UsbToIpaPipe, &m_IpaToUsbPipeAgg, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class MBIMAggregation0LimitsTest: public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMAggregation0LimitsTest(bool generic_agg)
+		: MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMAggregation0LimitsTest";
+		else
+			m_name = "MBIMAggregation0LimitsTest";
+		m_description = "MBIM Aggregation 0 limits test - sends 5 packets and expects"
+				"to get each packet back aggregated (both size and time limits are 0)";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRules1HeaderAggregation0Limits();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMAggregation0LimitsTest(
+				&m_UsbToIpaPipe, &m_IpaToUsbPipeAgg0Limits, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class MBIMAggregationDifferentStreamIdsTest:
+	public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMAggregationDifferentStreamIdsTest(bool generic_agg)
+		: MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMAggregationDifferentStreamIdsTest";
+		else
+			m_name = "MBIMAggregationDifferentStreamIdsTest";
+		m_description = "MBIM Aggregation different stream IDs test - sends 5 packets"
+				"with different stream IDs and receives 1 aggregated packet made of 5"
+				"NDPs";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		m_eIP = IPA_IP_v4;
+		const char aBypass[NUM_PACKETS][20] = {{"Bypass1"}, {"Bypass2"}, {"Bypass3"},
+				{"Bypass4"}, {"Bypass5"}};
+		uint32_t nTableHdl[NUM_PACKETS];
+		bool bRetVal = true;
+		IPAFilteringTable cFilterTable0;
+		struct ipa_flt_rule_add sFilterRuleEntry;
+		struct ipa_ioc_get_hdr sGetHeader[NUM_PACKETS];
+		uint8_t aHeadertoAdd[NUM_PACKETS][4];
+		int hdrSize;
+
+		for (int i = 0; i < NUM_PACKETS; i++) {
+			if (mGenericAgg) {
+				hdrSize = 4;
+				aHeadertoAdd[i][0] = 0x49;
+				aHeadertoAdd[i][1] = 0x50;
+				aHeadertoAdd[i][2] = 0x53;
+				aHeadertoAdd[i][3] = (uint8_t)i;
+			} else {
+				hdrSize = 1;
+				aHeadertoAdd[i][0] = (uint8_t)i;
+			}
+		}
+
+		LOG_MSG_STACK("Entering Function");
+		memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+		for (int i = 0; i < NUM_PACKETS; i++)
+			memset(&sGetHeader[i], 0, sizeof(sGetHeader[i]));
+		// Create Header:
+		// Allocate Memory, populate it, and add in to the Header Insertion.
+		struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+		pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+				sizeof(struct ipa_ioc_add_hdr)
+						+ NUM_PACKETS * sizeof(struct ipa_hdr_add));
+		if (!pHeaderDescriptor)
+		{
+			LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+			bRetVal = false;
+			goto bail;
+		}
+
+		pHeaderDescriptor->commit = true;
+		pHeaderDescriptor->num_hdrs = NUM_PACKETS;
+		// Adding Header No1.
+		strlcpy(pHeaderDescriptor->hdr[0].name, "StreamId0", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+		memcpy(pHeaderDescriptor->hdr[0].hdr, (void*)&aHeadertoAdd[0],
+				hdrSize); //Header's Data
+		pHeaderDescriptor->hdr[0].hdr_len = hdrSize;
+		pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+		pHeaderDescriptor->hdr[0].is_partial = false;
+		pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+		// Adding Header No2.
+		strlcpy(pHeaderDescriptor->hdr[1].name, "StreamId1", sizeof(pHeaderDescriptor->hdr[1].name)); // Header's Name
+		memcpy(pHeaderDescriptor->hdr[1].hdr, (void*)&aHeadertoAdd[1],
+			hdrSize); //Header's Data
+		pHeaderDescriptor->hdr[1].hdr_len = hdrSize;
+		pHeaderDescriptor->hdr[1].hdr_hdl    = -1; //Return Value
+		pHeaderDescriptor->hdr[1].is_partial = false;
+		pHeaderDescriptor->hdr[1].status     = -1; // Return Parameter
+
+		// Adding Header No3.
+		strlcpy(pHeaderDescriptor->hdr[2].name, "StreamId2", sizeof(pHeaderDescriptor->hdr[2].name)); // Header's Name
+		memcpy(pHeaderDescriptor->hdr[2].hdr, (void*)&aHeadertoAdd[2],
+			hdrSize); //Header's Data
+		pHeaderDescriptor->hdr[2].hdr_len = hdrSize;
+		pHeaderDescriptor->hdr[2].hdr_hdl    = -1; //Return Value
+		pHeaderDescriptor->hdr[2].is_partial = false;
+		pHeaderDescriptor->hdr[2].status     = -1; // Return Parameter
+
+		// Adding Header No4.
+		strlcpy(pHeaderDescriptor->hdr[3].name, "StreamId3", sizeof(pHeaderDescriptor->hdr[3].name)); // Header's Name
+		memcpy(pHeaderDescriptor->hdr[3].hdr, (void*)&aHeadertoAdd[3],
+			hdrSize); //Header's Data
+		pHeaderDescriptor->hdr[3].hdr_len = hdrSize;
+		pHeaderDescriptor->hdr[3].hdr_hdl    = -1; //Return Value
+		pHeaderDescriptor->hdr[3].is_partial = false;
+		pHeaderDescriptor->hdr[3].status     = -1; // Return Parameter
+
+		// Adding Header No5.
+		strlcpy(pHeaderDescriptor->hdr[4].name, "StreamId4", sizeof(pHeaderDescriptor->hdr[4].name)); // Header's Name
+		memcpy(pHeaderDescriptor->hdr[4].hdr, (void*)&aHeadertoAdd[4],
+			hdrSize); //Header's Data
+		pHeaderDescriptor->hdr[4].hdr_len = hdrSize;
+		pHeaderDescriptor->hdr[4].hdr_hdl    = -1; //Return Value
+		pHeaderDescriptor->hdr[4].is_partial = false;
+		pHeaderDescriptor->hdr[4].status     = -1; // Return Parameter
+
+		for (int i = 0; i < NUM_PACKETS; i++)
+			strlcpy(sGetHeader[i].name, pHeaderDescriptor->hdr[i].name, sizeof(sGetHeader[i].name));
+
+
+		if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+		{
+			LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader[i]))
+			{
+				LOG_MSG_ERROR(" Failed");
+				bRetVal = false;
+				goto bail;
+			}
+			LOG_MSG_DEBUG("Received Header %d Handle = 0x%x", i, sGetHeader[i].hdl);
+		}
+
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			if (!CreateBypassRoutingTable(&m_Routing, m_eIP, aBypass[i],
+					IPA_CLIENT_TEST2_CONS, sGetHeader[i].hdl,&nTableHdl[i]))
+			{
+				LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+				bRetVal = false;
+				goto bail;
+			}
+		}
+
+		LOG_MSG_INFO("Creation of 5 bypass routing tables completed successfully");
+
+		// Creating Filtering Rules
+		cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST_PROD, false, NUM_PACKETS);
+		LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+		// Configuring Filtering Rule No.1
+		cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+		sFilterRuleEntry.at_rear = true;
+		sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+		sFilterRuleEntry.status = -1; // return value
+		sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+		sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl[0]; //put here the handle corresponding to Routing Rule 1
+		sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+		sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		if (
+				((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+				!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+				)
+		{
+			LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n",
+					cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,
+					cFilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+		sFilterRuleEntry.status = -1; // return Value
+		sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl[1]; //put here the handle corresponding to Routing Rule 2
+		sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0xC0A80101; // Filter DST_IP == 192.168.1.1.
+		if (
+				((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+				!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR ("Adding Rule(1) to Filtering block Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n",
+					cFilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,
+					cFilterTable0.ReadRuleFromTable(1)->status);
+		}
+
+		// Configuring Filtering Rule No.3
+		sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+		sFilterRuleEntry.status = -1; // return value
+		sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl[2]; //put here the handle corresponding to Routing Rule 2
+		sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0xC0A80102; // Filter DST_IP == 192.168.1.2.
+
+		if (
+				((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+				!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR ("Adding Rule(2) to Filtering block Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n",
+					cFilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,
+					cFilterTable0.ReadRuleFromTable(2)->status);
+		}
+
+		// Configuring Filtering Rule No.4
+		sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+		sFilterRuleEntry.status = -1; // return value
+		sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl[3]; //put here the handle corresponding to Routing Rule 2
+		sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0xC0A80103; // Filter DST_IP == 192.168.1.3.
+
+		if (
+				((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+				!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR ("Adding Rule(3) to Filtering block Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n",
+					cFilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,
+					cFilterTable0.ReadRuleFromTable(2)->status);
+		}
+
+		// Configuring Filtering Rule No.5
+		sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+		sFilterRuleEntry.status = -1; // return value
+		sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl[4]; //put here the handle corresponding to Routing Rule 2
+		sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0xC0A80104; // Filter DST_IP == 192.168.1.4.
+
+		if (
+				((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+				!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR ("Adding Rule(4) to Filtering block Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n",
+					cFilterTable0.ReadRuleFromTable(2)->flt_rule_hdl,
+					cFilterTable0.ReadRuleFromTable(2)->status);
+		}
+
+	bail:
+		Free(pHeaderDescriptor);
+		LOG_MSG_STACK(
+				"Leaving Function (Returning %s)", bRetVal?"True":"False");
+		return bRetVal;
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMAggregationDifferentStreamIdsTest(
+				&m_UsbToIpaPipe, &m_IpaToUsbPipeAgg, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class MBIMAggregationNoInterleavingStreamIdsTest:
+	public MBIMAggregationTestFixtureConf11 {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	MBIMAggregationNoInterleavingStreamIdsTest(bool generic_agg)
+		: MBIMAggregationTestFixtureConf11(generic_agg)
+	{
+		if (generic_agg)
+			m_name = "GenMBIMAggregationNoInterleavingStreamIdsTest";
+		else
+			m_name = "MBIMAggregationNoInterleavingStreamIdsTest";
+		m_description = "MBIM Aggregation no interleaving stream IDs test - sends 5 packets"
+				"with interleaving stream IDs (0, 1, 0, 1, 0) and receives 1 aggregated "
+				"packet made of 5 NDPs";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		m_eIP = IPA_IP_v4;
+		const char aBypass[2][20] = {{"Bypass1"}, {"Bypass2"}};
+		uint32_t nTableHdl[2];
+		bool bRetVal = true;
+		IPAFilteringTable cFilterTable0;
+		struct ipa_flt_rule_add sFilterRuleEntry;
+		struct ipa_ioc_get_hdr sGetHeader[2];
+		uint8_t aHeadertoAdd[2][4];
+		int hdrSize;
+
+		for (int i = 0; i < 2; i++) {
+			if (mGenericAgg) {
+				hdrSize = 4;
+				aHeadertoAdd[i][0] = 0x49;
+				aHeadertoAdd[i][1] = 0x50;
+				aHeadertoAdd[i][2] = 0x53;
+				aHeadertoAdd[i][3] = (uint8_t)i;
+			}
+			else {
+				hdrSize = 1;
+				aHeadertoAdd[i][0] = (uint8_t)i;
+			}
+		}
+
+		LOG_MSG_STACK("Entering Function");
+		memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+		for (int i = 0; i < 2; i++)
+			memset(&sGetHeader[i], 0, sizeof(sGetHeader[i]));
+		// Create Header:
+		// Allocate Memory, populate it, and add in to the Header Insertion.
+		struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+		pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+				sizeof(struct ipa_ioc_add_hdr)
+						+ 2 * sizeof(struct ipa_hdr_add));
+		if (!pHeaderDescriptor)
+		{
+			LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+			bRetVal = false;
+			goto bail;
+		}
+
+		pHeaderDescriptor->commit = true;
+		pHeaderDescriptor->num_hdrs = 2;
+		// Adding Header No1.
+		strlcpy(pHeaderDescriptor->hdr[0].name, "StreamId0", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+		memcpy(pHeaderDescriptor->hdr[0].hdr, (void*)&aHeadertoAdd[0],
+			hdrSize); //Header's Data
+		pHeaderDescriptor->hdr[0].hdr_len = hdrSize;
+		pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+		pHeaderDescriptor->hdr[0].is_partial = false;
+		pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+		// Adding Header No2.
+		strlcpy(pHeaderDescriptor->hdr[1].name, "StreamId1", sizeof(pHeaderDescriptor->hdr[1].name)); // Header's Name
+		memcpy(pHeaderDescriptor->hdr[1].hdr, (void*)&aHeadertoAdd[1],
+			hdrSize); //Header's Data
+		pHeaderDescriptor->hdr[1].hdr_len = hdrSize;
+		pHeaderDescriptor->hdr[1].hdr_hdl    = -1; //Return Value
+		pHeaderDescriptor->hdr[1].is_partial = false;
+		pHeaderDescriptor->hdr[1].status     = -1; // Return Parameter
+
+		for (int i = 0; i < 2; i++)
+			strlcpy(sGetHeader[i].name, pHeaderDescriptor->hdr[i].name, sizeof(sGetHeader[i].name));
+
+
+		if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+		{
+			LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+		for (int i = 0; i < 2; i++)
+		{
+			if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader[i]))
+			{
+				LOG_MSG_ERROR(" Failed");
+				bRetVal = false;
+				goto bail;
+			}
+			LOG_MSG_DEBUG("Received Header %d Handle = 0x%x", i, sGetHeader[i].hdl);
+		}
+
+		for (int i = 0; i < 2; i++)
+		{
+			if (!CreateBypassRoutingTable(&m_Routing, m_eIP, aBypass[i],
+					IPA_CLIENT_TEST2_CONS, sGetHeader[i].hdl,&nTableHdl[i]))
+			{
+				LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+				bRetVal = false;
+				goto bail;
+			}
+		}
+
+		LOG_MSG_INFO("Creation of 2 bypass routing tables completed successfully");
+
+		// Creating Filtering Rules
+		cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST_PROD, false, 2);
+		LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+		// Configuring Filtering Rule No.1
+		cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+		sFilterRuleEntry.at_rear = true;
+		sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+		sFilterRuleEntry.status = -1; // return value
+		sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+		sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl[0]; //put here the handle corresponding to Routing Rule 1
+		sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+		sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+		sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+		if (
+				((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+				!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+				)
+		{
+			LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n",
+					cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,
+					cFilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		// Configuring Filtering Rule No.2
+		sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+		sFilterRuleEntry.status = -1; // return Value
+		sFilterRuleEntry.rule.rt_tbl_hdl=nTableHdl[1]; //put here the handle corresponding to Routing Rule 2
+		sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0xC0A80101; // Filter DST_IP == 192.168.1.1.
+		if (
+				((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+				!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR ("Adding Rule(1) to Filtering block Failed.");
+			bRetVal = false;
+			goto bail;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n",
+					cFilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,
+					cFilterTable0.ReadRuleFromTable(1)->status);
+		}
+
+	bail:
+		Free(pHeaderDescriptor);
+		LOG_MSG_STACK(
+				"Leaving Function (Returning %s)", bRetVal?"True":"False");
+		return bRetVal;
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		return MBIMAggregationScenarios::MBIMAggregationNoInterleavingStreamIdsTest(
+				&m_UsbToIpaPipe, &m_IpaToUsbPipeAgg, m_eIP);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/* Legacy MBIM tests */
+
+static MBIMAggregationTest mbimAggregationTest(false);
+static MBIMDeaggregationTest mbimDeaggregationTest(false);
+static MBIMDeaggregationOnePacketTest mbimDeaggregationOnePacketTest(false);
+static MBIMDeaggregationAndAggregationTest mbimDeaggregationAndAggregationTest(false);
+static MBIMMultipleDeaggregationAndAggregationTest
+		mbimMultipleDeaggregationAndAggregationTest(false);
+static MBIMAggregationLoopTest mbimAggregationLoopTest(false);
+static MBIMDeaggregationMultipleNDPTest mbimDeaggregationMultipleNDPTest(false);
+static MBIMAggregationMultiplePacketsTest mbimAggregationMultiplePacketsTest(false);
+static MBIMAggregation2PipesTest mbimAggregation2PipesTest(false);
+static MBIMAggregationNoInterleavingStreamIdsTest
+		mbimAggregationNoInterleavingStreamIdsTest(false);
+static MBIMAggregationDifferentStreamIdsTest mbimAggregationDifferentStreamIdsTest(false);
+static MBIMAggregationTimeLimitTest mbimAggregationTimeLimitTest(false);
+static MBIMAggregationByteLimitTest mbimAggregationByteLimitTest(false);
+static MBIMAggregationTimeLimitLoopTest mbimAggregationTimeLimitLoopTest(false);
+static MBIMAggregation0LimitsTest mbimAggregation0LimitsTest(false);
+
+/* Generic Aggregation MBIM tests */
+
+static MBIMAggregationTest genMbimAggregationTest(true);
+static MBIMDeaggregationTest genMbimDeaggregationTest(true);
+static MBIMDeaggregationOnePacketTest genMbimDeaggregationOnePacketTest(true);
+static MBIMDeaggregationAndAggregationTest genMbimDeaggregationAndAggregationTest(true);
+static MBIMMultipleDeaggregationAndAggregationTest genMbimMultipleDeaggregationAndAggregationTest(true);
+static MBIMAggregationLoopTest genMbimAggregationLoopTest(true);
+static MBIMDeaggregationMultipleNDPTest genMbimDeaggregationMultipleNDPTest(true);
+static MBIMAggregationMultiplePacketsTest genMbimAggregationMultiplePacketsTest(true);
+static MBIMAggregation2PipesTest genMbimAggregation2PipesTest(true);
+static MBIMAggregationNoInterleavingStreamIdsTest genMbimAggregationNoInterleavingStreamIdsTest(true);
+static MBIMAggregationDifferentStreamIdsTest genMbimAggregationDifferentStreamIdsTest(true);
+static MBIMAggregationTimeLimitTest genMbimAggregationTimeLimitTest(true);
+static MBIMAggregationByteLimitTest genMbimAggregationByteLimitTest(true);
+static MBIMAggregationByteLimitTestFC genMbimAggregationByteLimitTestFC(true);
+static MBIMAggregationDualDpTestFC genMBIMAggregationDualDpTestFC(true);
+static MBIMAggregationDualDpTestFcRoutingBased genMBIMAggregationDualDpTestFcRoutingBased(true);
+static MBIMAggregationTimeLimitLoopTest genMbimAggregationTimeLimitLoopTest(true);
+static MBIMAggregation0LimitsTest genMbimAggregation0LimitsTest(true);
+
+/////////////////////////////////////////////////////////////////////////////////
+//                                  EOF                                      ////
+/////////////////////////////////////////////////////////////////////////////////

+ 51 - 0
kernel-tests/Makefile.am

@@ -0,0 +1,51 @@
+ACLOCAL_AMFLAGS = -Im4
+EXTRA_CFLAGS	 = -DDEBUG
+AM_CXXFLAGS = -Wall -Wundef -Wno-trigraphs -Werror
+
+if USE_GLIB
+    ipa_kernel_tests_CPPFLAGS  = $(AM_CFLAGS) -DUSE_GLIB -Dstrlcpy=g_strlcpy @GLIB_CFLAGS@
+    ipa_kernel_tests_LDFLAGS = -lpthread @GLIB_LIBS@
+endif
+
+requiredlibs = -lipanat
+ipa_kernel_tests_LDADD =  $(requiredlibs)
+
+ipa_kernel_testsdir            = $(prefix)
+ipa_kernel_tests_PROGRAMS      = ipa_kernel_tests
+dist_ipa_kernel_tests_SCRIPTS  = run.sh
+ipa_kernel_tests_SOURCES =\
+		TestManager.cpp \
+		TestBase.cpp \
+		InterfaceAbstraction.cpp \
+		Pipe.cpp \
+		PipeTestFixture.cpp \
+		PipeTests.cpp \
+		TLPAggregationTestFixture.cpp \
+		TLPAggregationTests.cpp \
+		MBIMAggregationTestFixtureConf11.cpp \
+		MBIMAggregationTests.cpp \
+		Logger.cpp \
+		RoutingDriverWrapper.cpp \
+		RoutingTests.cpp \
+		IPAFilteringTable.cpp \
+		Filtering.cpp \
+		FilteringTest.cpp \
+		HeaderInsertion.cpp \
+		HeaderInsertionTests.cpp \
+		TestsUtils.cpp \
+		HeaderRemovalTestFixture.cpp \
+		HeaderRemovalTests.cpp \
+		IPv4Packet.cpp \
+		RNDISAggregationTestFixture.cpp \
+		RNDISAggregationTests.cpp \
+		DataPathTestFixture.cpp \
+		DataPathTests.cpp \
+		IPAInterruptsTestFixture.cpp \
+		IPAInterruptsTests.cpp \
+		HeaderProcessingContextTestFixture.cpp \
+		HeaderProcessingContextTests.cpp \
+		FilteringEthernetBridgingTestFixture.cpp \
+		FilteringEthernetBridgingTests.cpp \
+		NatTest.cpp \
+		IPv6CTTest.cpp \
+		main.cpp

+ 26 - 0
kernel-tests/NOTICE

@@ -0,0 +1,26 @@
+Copyright (c) 2021 The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 4288 - 0
kernel-tests/NatTest.cpp

@@ -0,0 +1,4288 @@
+/*
+ * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <cstring> // for memcpy
+#include "hton.h" // for htonl
+#include "InterfaceAbstraction.h"
+#include "Constants.h"
+#include "Logger.h"
+#include "TestsUtils.h"
+#include "Filtering.h"
+#include "RoutingDriverWrapper.h"
+#include "IPAFilteringTable.h"
+extern "C" {
+#include "ipa_nat_drv.h"
+}
+
+//IP offsets
+#define IPV4_PROTOCOL_OFFSET (9)
+#define IPV4_IP_CHECKSUM_OFFSET (10)
+#define IPV4_SRC_ADDR_OFFSET (12)
+#define IPV4_DST_ADDR_OFFSET (16)
+
+//TCP offsets
+#define IPV4_SRC_PORT_OFFSET (20)
+#define IPV4_DST_PORT_OFFSET (20+2)
+#define IPV4_TCP_FLAGS_OFFSET (33)
+#define IPV4_TCP_CHECKSUM_OFFSET (36)
+
+#define IPA_16BIT_ROUND_UP(val) \
+	do { \
+		if (val >> 16) { \
+			val = (val & 0x0000FFFF);\
+			val += 1;\
+		} \
+	} while(0)
+
+extern Logger g_Logger;
+
+class IpaNatBlockTestFixture : public TestBase
+{
+public:
+
+	IpaNatBlockTestFixture() :
+		m_sendSize(BUFF_MAX_SIZE),
+		m_sendSize2(BUFF_MAX_SIZE),
+		m_sendSize3(BUFF_MAX_SIZE),
+		m_IpaIPType(IPA_IP_v4),
+		m_extHdrType(NONE)
+	{
+		memset(m_sendBuffer, 0, sizeof(m_sendBuffer));	// First input file / IP packet
+		memset(m_sendBuffer2, 0, sizeof(m_sendBuffer2));	// Second input file / IP packet
+		memset(m_sendBuffer3, 0, sizeof(m_sendBuffer3));	// Third input file (default) / IP packet
+		m_testSuiteName.push_back("Nat");
+	}
+
+	static int SetupKernelModule(bool en_status = 0)
+	{
+		int retval;
+		struct ipa_channel_config from_ipa_channels[3];
+		struct test_ipa_ep_cfg from_ipa_cfg[3];
+		struct ipa_channel_config to_ipa_channels[2];
+		struct test_ipa_ep_cfg to_ipa_cfg[2];
+
+		struct ipa_test_config_header header = { 0 };
+		struct ipa_channel_config *to_ipa_array[2];
+		struct ipa_channel_config *from_ipa_array[3];
+
+		/* From ipa configurations - 3 pipes */
+		memset(&from_ipa_cfg[0], 0, sizeof(from_ipa_cfg[0]));
+		prepare_channel_struct(&from_ipa_channels[0],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST2_CONS,
+			(void *)&from_ipa_cfg[0],
+			sizeof(from_ipa_cfg[0]),
+			en_status);
+		from_ipa_array[0] = &from_ipa_channels[0];
+
+		memset(&from_ipa_cfg[1], 0, sizeof(from_ipa_cfg[1]));
+		prepare_channel_struct(&from_ipa_channels[1],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST3_CONS,
+			(void *)&from_ipa_cfg[1],
+			sizeof(from_ipa_cfg[1]),
+			en_status);
+		from_ipa_array[1] = &from_ipa_channels[1];
+
+		memset(&from_ipa_cfg[2], 0, sizeof(from_ipa_cfg[2]));
+		prepare_channel_struct(&from_ipa_channels[2],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST4_CONS,
+			(void *)&from_ipa_cfg[2],
+			sizeof(from_ipa_cfg[2]),
+			en_status);
+		from_ipa_array[2] = &from_ipa_channels[2];
+
+		/* To ipa configurations - 2 pipes */
+		memset(&to_ipa_cfg[0], 0, sizeof(to_ipa_cfg[0]));
+		prepare_channel_struct(&to_ipa_channels[0],
+			header.to_ipa_channels_num++,
+			IPA_CLIENT_TEST_PROD,
+			(void *)&to_ipa_cfg[0],
+			sizeof(to_ipa_cfg[0]));
+		to_ipa_array[0] = &to_ipa_channels[0];
+
+		/* header removal for Ethernet header + 8021Q header */
+		memset(&to_ipa_cfg[1], 0, sizeof(to_ipa_cfg[1]));
+		to_ipa_cfg[1].hdr.hdr_len = ETH8021Q_HEADER_LEN;
+		to_ipa_cfg[1].hdr.hdr_ofst_metadata_valid = 1;
+		to_ipa_cfg[1].hdr.hdr_ofst_metadata =
+			ETH8021Q_METADATA_OFFSET;
+		prepare_channel_struct(&to_ipa_channels[1],
+			header.to_ipa_channels_num++,
+			IPA_CLIENT_TEST2_PROD,
+			(void *)&to_ipa_cfg[1],
+			sizeof(to_ipa_cfg[1]));
+		to_ipa_array[1] = &to_ipa_channels[1];
+
+		prepare_header_struct(&header, from_ipa_array, to_ipa_array);
+
+		retval = GenericConfigureScenario(&header);
+
+		return retval;
+	}
+
+	bool Setup()
+	{
+		bool bRetVal = true;
+
+		if (SetupKernelModule() != true)
+			return bRetVal;
+
+		m_producer.Open(INTERFACE0_TO_IPA_DATA_PATH, INTERFACE0_FROM_IPA_DATA_PATH);
+		m_producer2.Open(INTERFACE4_TO_IPA_DATA_PATH, INTERFACE4_FROM_IPA_DATA_PATH);
+
+		m_consumer.Open(INTERFACE1_TO_IPA_DATA_PATH, INTERFACE1_FROM_IPA_DATA_PATH);
+		m_consumer2.Open(INTERFACE2_TO_IPA_DATA_PATH, INTERFACE2_FROM_IPA_DATA_PATH);
+		m_defaultConsumer.Open(INTERFACE3_TO_IPA_DATA_PATH, INTERFACE3_FROM_IPA_DATA_PATH);
+
+		if (!m_routing.DeviceNodeIsOpened())
+		{
+			LOG_MSG_ERROR("Routing block is not ready for immediate commands!\n");
+			return false;
+		}
+
+		if (!m_filtering.DeviceNodeIsOpened())
+		{
+			LOG_MSG_ERROR("Filtering block is not ready for immediate commands!\n");
+			return false;
+		}
+		m_routing.Reset(IPA_IP_v4); // This will issue a Reset command to the Filtering as well
+		m_routing.Reset(IPA_IP_v6); // This will issue a Reset command to the Filtering as well
+		return true;
+	} // Setup()
+
+	bool Setup(bool en_status = false)
+	{
+		bool bRetVal = true;
+
+		if (SetupKernelModule(en_status) != true)
+			return bRetVal;
+
+		m_producer.Open(INTERFACE0_TO_IPA_DATA_PATH, INTERFACE0_FROM_IPA_DATA_PATH);
+
+		m_consumer.Open(INTERFACE1_TO_IPA_DATA_PATH, INTERFACE1_FROM_IPA_DATA_PATH);
+		m_consumer2.Open(INTERFACE2_TO_IPA_DATA_PATH, INTERFACE2_FROM_IPA_DATA_PATH);
+		m_defaultConsumer.Open(INTERFACE3_TO_IPA_DATA_PATH, INTERFACE3_FROM_IPA_DATA_PATH);
+
+		if (!m_routing.DeviceNodeIsOpened())
+		{
+			LOG_MSG_ERROR("Routing block is not ready for immediate commands!\n");
+			return false;
+		}
+
+		if (!m_filtering.DeviceNodeIsOpened())
+		{
+			LOG_MSG_ERROR("Filtering block is not ready for immediate commands!\n");
+			return false;
+		}
+		m_routing.Reset(IPA_IP_v4); // This will issue a Reset command to the Filtering as well
+		m_routing.Reset(IPA_IP_v6); // This will issue a Reset command to the Filtering as well
+		return true;
+	} // Setup()
+
+	bool Teardown()
+	{
+		ipa_nat_dump_ipv4_table(m_tbl_hdl);
+		ipa_nat_del_ipv4_tbl(m_tbl_hdl);
+
+		m_producer.Close();
+		m_producer2.Close();
+		m_consumer.Close();
+		m_consumer2.Close();
+		m_defaultConsumer.Close();
+		return true;
+	} // Teardown()
+
+	virtual bool LoadFiles(enum ipa_ip_type ip)
+	{
+		string fileName;
+
+		if (IPA_IP_v4 == ip) {
+			fileName = "Input/IPv4_1";
+		}
+		else {
+			fileName = "Input/IPv6";
+		}
+
+		if (!LoadDefaultPacket(ip, m_extHdrType, m_sendBuffer, m_sendSize)) {
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("Loaded %zu Bytes to Buffer 1\n", m_sendSize);
+
+		if (!LoadDefaultPacket(ip, m_extHdrType, m_sendBuffer2, m_sendSize2)) {
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("Loaded %zu Bytes to Buffer 2\n", m_sendSize2);
+
+		if (!LoadDefaultPacket(ip, m_extHdrType, m_sendBuffer3, m_sendSize3)) {
+			LOG_MSG_ERROR("Failed default Packet\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("Loaded %zu Bytes to Buffer 3\n", m_sendSize3);
+
+		return true;
+	}
+
+	inline bool VerifyStatusReceived(size_t SendSize, size_t RecvSize)
+	{
+		size_t stts_size = sizeof(struct ipa3_hw_pkt_status);
+
+		if (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) {
+			stts_size = sizeof(struct ipa3_hw_pkt_status_hw_v5_0);
+		}
+
+		if ((RecvSize <= SendSize) ||
+			((RecvSize - SendSize) != stts_size)) {
+			LOG_MSG_ERROR("received buffer size does not match! sent:receive [%zu]:[%zu]\n", SendSize, RecvSize);
+			return false;
+		}
+
+		return true;
+	}
+
+	inline bool IsCacheHit(size_t SendSize, size_t RecvSize, void *Buff)
+	{
+		struct ipa3_hw_pkt_status *pStatus = (struct ipa3_hw_pkt_status *)Buff;
+
+		if (VerifyStatusReceived(SendSize, RecvSize) == false) {
+			return false;
+		}
+
+		if ((bool)pStatus->route_hash) {
+			LOG_MSG_DEBUG("cache hit!! \n");
+			return true;
+		}
+
+		LOG_MSG_ERROR("cache miss!! \n");
+		return false;
+
+	}
+	
+	inline bool IsCacheHit_v5_0(size_t SendSize, size_t RecvSize, void *Buff)
+	{
+		struct ipa3_hw_pkt_status_hw_v5_0 *pStatus = (struct ipa3_hw_pkt_status_hw_v5_0 *)Buff;
+
+		if (VerifyStatusReceived(SendSize, RecvSize) == false) {
+			return false;
+		}
+
+		if ((bool)pStatus->route_hash) {
+			LOG_MSG_DEBUG("cache hit!! \n");
+			return true;
+		}
+
+		LOG_MSG_ERROR("cache miss!! \n");
+		return false;
+
+	}
+
+	inline bool IsCacheMiss(size_t SendSize, size_t RecvSize, void *Buff)
+	{
+		struct ipa3_hw_pkt_status *pStatus = (struct ipa3_hw_pkt_status *)Buff;
+
+		if (VerifyStatusReceived(SendSize, RecvSize) == false) {
+			return false;
+		}
+
+		if (!((bool)pStatus->route_hash)) {
+			LOG_MSG_DEBUG("cache miss!! \n");
+			return true;
+		}
+
+		LOG_MSG_ERROR("cache hit!! \n");
+		return false;
+	}
+	
+	inline bool IsCacheMiss_v5_0(size_t SendSize, size_t RecvSize, void *Buff)
+	{
+		struct ipa3_hw_pkt_status_hw_v5_0 *pStatus = (struct ipa3_hw_pkt_status_hw_v5_0 *)Buff;
+
+		if (VerifyStatusReceived(SendSize, RecvSize) == false) {
+			return false;
+		}
+
+		if (!((bool)pStatus->route_hash)) {
+			LOG_MSG_DEBUG("cache miss!! \n");
+			return true;
+		}
+
+		LOG_MSG_ERROR("cache hit!! \n");
+		return false;
+	}
+
+	bool CompareResultVsGoldenNat(Byte *goldenBuffer, unsigned int goldenSize,
+		Byte *receivedBuffer, unsigned int receivedSize, int private_ip, int public_ip,
+		int private_port, int public_port, bool src_nat, int IPv4_offset = 0, bool with_status = false)
+	{
+		bool result;
+		uint32_t address;
+		uint16_t port;
+		uint32_t val;
+		uint16_t ip_checksum_diff, tcp_checksum_diff;
+		uint32_t ip_checksum, tcp_checksum;
+		int recv_offset = 0;
+		size_t stts_size = sizeof(struct ipa3_hw_pkt_status);
+
+		if (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) {
+			stts_size = sizeof(struct ipa3_hw_pkt_status_hw_v5_0);
+		}
+
+		if (with_status)
+			recv_offset += stts_size;
+
+		ip_checksum_diff = calc_ip_cksum_diff(public_ip, private_ip);
+		tcp_checksum_diff = calc_tcp_udp_cksum_diff(public_ip, public_port, private_ip, private_port);
+
+		//calculate new ip checksum, old checksum + 1's compliment of checksum diff
+		ip_checksum = *((uint16_t *)&goldenBuffer[IPV4_IP_CHECKSUM_OFFSET + IPv4_offset]);
+		ip_checksum = ntohs(ip_checksum);
+
+		if(src_nat)
+			ip_checksum += (uint16_t)(~ip_checksum_diff);
+		else
+			ip_checksum += (uint16_t)ip_checksum_diff;
+
+		IPA_16BIT_ROUND_UP(ip_checksum);
+
+		//return to network format
+		ip_checksum = htons(ip_checksum);
+
+		//calculate new tcp checksum, old checksum + 1's compliment of checksum diff
+		tcp_checksum = *((uint16_t *)&goldenBuffer[IPV4_TCP_CHECKSUM_OFFSET + IPv4_offset]);
+		tcp_checksum = ntohs(tcp_checksum);
+
+		if(src_nat)
+			tcp_checksum += (uint16_t)(~tcp_checksum_diff);
+		else
+			tcp_checksum += (uint16_t)tcp_checksum_diff;
+
+		IPA_16BIT_ROUND_UP(tcp_checksum);
+
+		//return to network format
+		tcp_checksum = htons(tcp_checksum);
+
+		if ((receivedSize - recv_offset) != goldenSize) {
+			g_Logger.AddMessage(LOG_VERBOSE, "%s Buffers sizes are different.\n", __FUNCTION__);
+			return false;
+		}
+
+		Byte *tmp_buff = new Byte[goldenSize];
+
+		memcpy(tmp_buff, goldenBuffer, goldenSize);
+
+		if (src_nat) {
+			address = htonl(public_ip);
+			port = htons(public_port);
+
+			memcpy(&tmp_buff[IPV4_SRC_ADDR_OFFSET + IPv4_offset], &address, sizeof(address));
+			memcpy(&tmp_buff[IPV4_SRC_PORT_OFFSET + IPv4_offset], &port, sizeof(port));
+
+			val = (*(uint32_t*)(&receivedBuffer[IPV4_SRC_ADDR_OFFSET + IPv4_offset + recv_offset]));
+			if (address != val)
+				LOG_MSG_ERROR("received src ip 0x%X != 0x%X\n", val, address);
+
+			val = (*(uint16_t*)(&receivedBuffer[IPV4_SRC_PORT_OFFSET + IPv4_offset + recv_offset]));
+			if (port != val)
+				LOG_MSG_ERROR("received src port %d != %d\n", val, port);
+		}
+		else {
+			address = htonl(private_ip);
+			port = htons(private_port);
+
+			memcpy(&tmp_buff[IPV4_DST_ADDR_OFFSET + IPv4_offset], &address, sizeof(address));
+			memcpy(&tmp_buff[IPV4_DST_PORT_OFFSET + IPv4_offset], &port, sizeof(port));
+
+			val = (*(uint32_t*)(&receivedBuffer[IPV4_DST_ADDR_OFFSET + IPv4_offset + +recv_offset]));
+			if (address != val)
+				LOG_MSG_ERROR("received dst ip 0x%X != 0x%X\n", val, address);
+			val = (*(uint16_t*)(&receivedBuffer[IPV4_DST_PORT_OFFSET + IPv4_offset + recv_offset]));
+			if (port != val)
+				LOG_MSG_ERROR("received dst port %d != %d\n", val, port);
+		}
+
+		memcpy(&tmp_buff[IPV4_IP_CHECKSUM_OFFSET + IPv4_offset], &ip_checksum, sizeof(uint16_t));
+		val  = (*(uint16_t*)(&receivedBuffer[IPV4_IP_CHECKSUM_OFFSET + IPv4_offset + recv_offset]));
+		if (ip_checksum != val)
+			LOG_MSG_ERROR("received checksum %d != %d\n", val, ip_checksum);
+
+		memcpy(&tmp_buff[IPV4_TCP_CHECKSUM_OFFSET + IPv4_offset], &tcp_checksum, sizeof(uint16_t));
+		val = (*(uint16_t*)(&receivedBuffer[IPV4_TCP_CHECKSUM_OFFSET + IPv4_offset + recv_offset]));
+		if (tcp_checksum != val)
+			LOG_MSG_ERROR("received checksum %d != %d\n", val, tcp_checksum);
+
+		size_t j;
+		char tmpBuffer[512] = { 0 };
+
+		for (j = 0; j < receivedSize; j++)
+			snprintf(&tmpBuffer[3 * j], sizeof(tmpBuffer) - (3 * j + 1), " %02X", tmp_buff[j]);
+		LOG_MSG_STACK("expected packet should be (%zu)\n%s\n", receivedSize, tmpBuffer);
+
+		result = !memcmp((void*)tmp_buff, (void*)(receivedBuffer + recv_offset), goldenSize);
+		if (!result)
+			LOG_MSG_ERROR("buffers comparison failed!!\n");
+
+		delete[] tmp_buff;
+
+		return result;
+	}
+
+	bool CreateMetdataRoutingRule(const char * bypass0)
+	{
+		LOG_MSG_DEBUG("Entering\n");
+		struct ipa_ioc_add_rt_rule *rt_rule0 = NULL;
+		struct ipa_rt_rule_add *rt_rule_entry;
+
+		rt_rule0 = (struct ipa_ioc_add_rt_rule *)
+			calloc(1,
+				sizeof(struct ipa_ioc_add_rt_rule) +
+				1 * sizeof(struct ipa_rt_rule_add)
+			);
+		if (!rt_rule0) {
+			LOG_MSG_ERROR("calloc failed to allocate rt_rule0\n");
+			return false;
+		}
+
+		rt_rule0->num_rules = 1;
+		rt_rule0->ip = IPA_IP_v4;
+		rt_rule0->commit = true;
+		strlcpy(rt_rule0->rt_tbl_name, bypass0, sizeof(rt_rule0->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule0->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_META_DATA;
+		rt_rule_entry->rule.attrib.meta_data = m_metadata;
+		rt_rule_entry->rule.attrib.meta_data_mask = 0xFFFFFFFF;// Filter exact metadata value
+		if (false == m_routing.AddRoutingRule(rt_rule0))
+		{
+			LOG_MSG_ERROR("Routing rule addition(rt_rule0) failed!\n");
+			Free(rt_rule0);
+			return false;
+		}
+
+		Free(rt_rule0);
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}
+
+	bool CreateHashableRoutingRules(const char * bypass0)
+	{
+		LOG_MSG_DEBUG("Entering\n");
+		struct ipa_ioc_add_rt_rule *rt_rule0 = 0, *rt_rule1 = 0;
+		struct ipa_rt_rule_add *rt_rule_entry;
+
+		rt_rule0 = (struct ipa_ioc_add_rt_rule *)
+			calloc(1,
+				sizeof(struct ipa_ioc_add_rt_rule) +
+				2 * sizeof(struct ipa_rt_rule_add)
+			);
+		if (!rt_rule0) {
+			LOG_MSG_ERROR("calloc failed to allocate rt_rule0\n");
+			return false;
+		}
+
+		rt_rule0->num_rules = 2;
+		rt_rule0->ip = IPA_IP_v4;
+		rt_rule0->commit = true;
+		strlcpy(rt_rule0->rt_tbl_name, bypass0, sizeof(rt_rule0->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule0->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr = m_private_ip;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;// Exact match
+		rt_rule_entry->rule.hashable = 1;
+
+		rt_rule_entry = &rt_rule0->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr = m_private_ip2;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;// Exact match
+		rt_rule_entry->rule.hashable = 1;
+		if (false == m_routing.AddRoutingRule(rt_rule0))
+		{
+			LOG_MSG_ERROR("Routing rule addition(rt_rule0) failed!\n");
+			Free(rt_rule1);
+			Free(rt_rule0);
+			return false;
+		}
+
+		Free(rt_rule0);
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}
+
+	// This function creates three IPv4 bypass routing entries and commits them.
+	bool CreateThreeIPv4BypassRoutingTables(const char * bypass0, const char * bypass1, const char * bypass2)
+	{
+		LOG_MSG_DEBUG("Entering\n");
+		struct ipa_ioc_add_rt_rule *rt_rule0 = 0, *rt_rule1 = 0, *rt_rule2 = 0;
+		struct ipa_rt_rule_add *rt_rule_entry;
+
+		rt_rule0 = (struct ipa_ioc_add_rt_rule *)
+			calloc(1,
+				sizeof(struct ipa_ioc_add_rt_rule) +
+				1 * sizeof(struct ipa_rt_rule_add)
+			);
+		if (!rt_rule0) {
+			LOG_MSG_ERROR("calloc failed to allocate rt_rule0\n");
+			return false;
+		}
+		rt_rule1 = (struct ipa_ioc_add_rt_rule *)
+			calloc(1,
+				sizeof(struct ipa_ioc_add_rt_rule) +
+				1 * sizeof(struct ipa_rt_rule_add)
+			);
+		if (!rt_rule1) {
+			LOG_MSG_ERROR("calloc failed to allocate rt_rule1\n");
+			Free(rt_rule0);
+			return false;
+		}
+		rt_rule2 = (struct ipa_ioc_add_rt_rule *)
+			calloc(1,
+				sizeof(struct ipa_ioc_add_rt_rule) +
+				1 * sizeof(struct ipa_rt_rule_add)
+			);
+		if (!rt_rule2) {
+			LOG_MSG_ERROR("calloc failed to allocate rt_rule2\n");
+			Free(rt_rule0);
+			Free(rt_rule1);
+			return false;
+		}
+
+		rt_rule0->num_rules = 1;
+		rt_rule0->ip = IPA_IP_v4;
+		rt_rule0->commit = true;
+		strlcpy(rt_rule0->rt_tbl_name, bypass0, sizeof(rt_rule0->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule0->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr = 0xaabbccdd;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0x00000000;// All Packets will get a "Hit"
+		if (false == m_routing.AddRoutingRule(rt_rule0))
+		{
+			LOG_MSG_ERROR("Routing rule addition(rt_rule0) failed!\n");
+			Free(rt_rule2);
+			Free(rt_rule1);
+			Free(rt_rule0);
+			return false;
+		}
+
+
+		rt_rule1->num_rules = 1;
+		rt_rule1->ip = IPA_IP_v4;
+		rt_rule1->commit = true;
+		strlcpy(rt_rule1->rt_tbl_name, bypass1, sizeof(rt_rule1->rt_tbl_name));
+		rt_rule_entry = &rt_rule1->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr = 0xaabbccdd;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0x00000000;// All Packets will get a "Hit"
+		if (false == m_routing.AddRoutingRule(rt_rule1))
+		{
+			LOG_MSG_ERROR("Routing rule addition(rt_rule1) failed!\n");
+			Free(rt_rule2);
+			Free(rt_rule1);
+			Free(rt_rule0);
+			return false;
+		}
+
+
+		rt_rule2->num_rules = 1;
+		rt_rule2->ip = IPA_IP_v4;
+		rt_rule2->commit = true;
+		strlcpy(rt_rule2->rt_tbl_name, bypass2, sizeof(rt_rule2->rt_tbl_name));
+		rt_rule_entry = &rt_rule2->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr = 0xaabbccdd;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0x00000000;// All Packets will get a "Hit"
+		if (false == m_routing.AddRoutingRule(rt_rule2))
+		{
+			LOG_MSG_ERROR("Routing rule addition(rt_rule2) failed!\n");
+			Free(rt_rule2);
+			Free(rt_rule1);
+			Free(rt_rule0);
+			return false;
+		}
+
+
+		Free(rt_rule2);
+		Free(rt_rule1);
+		Free(rt_rule0);
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}
+
+	void Load8021QPacket()
+	{
+		m_sendSize = sizeof(m_sendBuffer);
+		LoadDefault802_1Q(IPA_IP_v4, m_sendBuffer, m_sendSize);
+	}
+
+	virtual bool ModifyPackets() = 0;
+	virtual bool AddRules() = 0;
+	virtual bool SendPackets() = 0;
+	virtual bool ReceivePacketsAndCompare() = 0;
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		LOG_MSG_DEBUG("Entering\n");
+
+		// Add the relevant filtering rules
+		res = AddRules();
+		if (false == res) {
+			LOG_MSG_ERROR("Failed adding filtering rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(m_IpaIPType);
+		if (false == res) {
+			LOG_MSG_ERROR("Failed loading files.\n");
+			return false;
+		}
+
+		res = ModifyPackets();
+		if (false == res) {
+			LOG_MSG_ERROR("Failed to modify packets.\n");
+			return false;
+		}
+
+		res = SendPackets();
+		if (res == false) {
+			LOG_MSG_ERROR("failed to send packets\n");
+			return false;
+		}
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		LOG_MSG_DEBUG("Returning %d\n", isSuccess);
+
+		return isSuccess;
+	} // Run()
+
+	  /**
+	  * calc_ip_cksum_diff() - Calculate the source nat
+	  * IP checksum diff
+	  * @pub_ip_addr: [in] public ip address
+	  * @priv_ip_addr: [in]	Private ip address
+	  *
+	  * source nat ip checksum different is calculated as
+	  * public_ip_addr - private_ip_addr
+	  * Here we are using 1's complement to represent -negative number.
+	  * So take 1's complement of private ip addr and add it
+	  * to public ip addr.
+	  *
+	  * Returns: >0 ip checksum diff
+	  */
+	uint16_t calc_ip_cksum_diff(uint32_t pub_ip_addr,
+		uint32_t priv_ip_addr)
+	{
+		uint16_t ret;
+		uint32_t cksum = 0;
+
+		/* Add LSB(2 bytes) of public ip address to cksum */
+		cksum += (pub_ip_addr & 0xFFFF);
+
+		/* Add MSB(2 bytes) of public ip address to cksum
+		and check for carry forward(CF), if any add it
+		*/
+		cksum += (pub_ip_addr >> 16);
+		IPA_16BIT_ROUND_UP(cksum);
+
+		/* Calculate the 1's complement of private ip address */
+		priv_ip_addr = (~priv_ip_addr);
+
+		/* Add LSB(2 bytes) of private ip address to cksum
+		and check for carry forward(CF), if any add it
+		*/
+		cksum += (priv_ip_addr & 0xFFFF);
+		IPA_16BIT_ROUND_UP(cksum);
+
+		/* Add MSB(2 bytes) of private ip address to cksum
+		and check for carry forward(CF), if any add it
+		*/
+		cksum += (priv_ip_addr >> 16);
+		IPA_16BIT_ROUND_UP(cksum);
+
+		/* Return the LSB(2 bytes) of checksum	*/
+		ret = (uint16_t)cksum;
+		return ret;
+	}
+
+	/**
+	* calc_tcp_udp_cksum() - Calculate the source nat
+	* TCP/UDP checksum diff
+	* @pub_ip_addr: [in] public ip address
+	* @pub_port: [in] public tcp/udp port
+	* @priv_ip_addr: [in]	Private ip address
+	* @priv_port: [in] Private tcp/udp prot
+	*
+	* source nat tcp/udp checksum is calculated as
+	* (pub_ip_addr + pub_port) - (priv_ip_addr + priv_port)
+	* Here we are using 1's complement to represent -ve number.
+	* So take 1's complement of prviate ip addr &private port
+	* and add it public ip addr & public port.
+	*
+	* Returns: >0 tcp/udp checksum diff
+	*/
+	uint16_t calc_tcp_udp_cksum_diff(uint32_t pub_ip_addr,
+		uint16_t pub_port,
+		uint32_t priv_ip_addr,
+		uint16_t priv_port)
+	{
+		uint16_t ret = 0;
+		uint32_t cksum = 0;
+
+		/* Add LSB(2 bytes) of public ip address to cksum */
+		cksum += (pub_ip_addr & 0xFFFF);
+
+		/* Add MSB(2 bytes) of public ip address to cksum
+		and check for carry forward(CF), if any add it
+		*/
+		cksum += (pub_ip_addr >> 16);
+		IPA_16BIT_ROUND_UP(cksum);
+
+		/* Add public port to cksum and
+		check for carry forward(CF), if any add it */
+		cksum += pub_port;
+		IPA_16BIT_ROUND_UP(cksum);
+
+		/* Calculate the 1's complement of private ip address */
+		priv_ip_addr = (~priv_ip_addr);
+
+		/* Add LSB(2 bytes) of private ip address to cksum
+		and check for carry forward(CF), if any add it
+		*/
+		cksum += (priv_ip_addr & 0xFFFF);
+		IPA_16BIT_ROUND_UP(cksum);
+
+		/* Add MSB(2 bytes) of private ip address to cksum
+		and check for carry forward(CF), if any add
+		*/
+		cksum += (priv_ip_addr >> 16);
+		IPA_16BIT_ROUND_UP(cksum);
+
+		/* Calculate the 1's complement of private port */
+		priv_port = (~priv_port);
+
+		/* Add public port to cksum and
+		check for carry forward(CF), if any add it */
+		cksum += priv_port;
+		IPA_16BIT_ROUND_UP(cksum);
+
+		/* return the LSB(2 bytes) of checksum */
+		ret = (uint16_t)cksum;
+		return ret;
+	}
+
+	~IpaNatBlockTestFixture()
+	{
+		m_sendSize = 0;
+		m_sendSize2 = 0;
+		m_sendSize3 = 0;
+	}
+
+	static Filtering m_filtering;
+	static RoutingDriverWrapper m_routing;
+	InterfaceAbstraction m_producer;
+	InterfaceAbstraction m_producer2;
+	InterfaceAbstraction m_consumer;
+	InterfaceAbstraction m_consumer2;
+	InterfaceAbstraction m_defaultConsumer;
+
+	static const size_t BUFF_MAX_SIZE = 1024;
+
+	Byte m_sendBuffer[BUFF_MAX_SIZE];	// First input file / IP packet
+	Byte m_sendBuffer2[BUFF_MAX_SIZE];	// Second input file / IP packet
+	Byte m_sendBuffer3[BUFF_MAX_SIZE];	// Third input file (default) / IP packet
+	size_t m_sendSize;
+	size_t m_sendSize2;
+	size_t m_sendSize3;
+	enum ipa_ip_type m_IpaIPType;
+	enum ipv6_ext_hdr_type m_extHdrType;
+	uint32_t m_tbl_hdl;
+	uint32_t m_nat_rule_hdl1;
+	uint32_t m_public_ip;
+	uint32_t m_public_ip2;
+	uint32_t m_private_ip;
+	uint32_t m_private_ip2;
+	uint32_t m_target_ip;
+	uint16_t m_public_port;
+	uint16_t m_public_port2;
+	uint16_t m_private_port;
+	uint16_t m_private_port2;
+	uint16_t m_target_port;
+	uint32_t m_metadata;
+private:
+};
+
+RoutingDriverWrapper IpaNatBlockTestFixture::m_routing;
+Filtering IpaNatBlockTestFixture::m_filtering;
+
+/*---------------------------------------------------------------------------*/
+/* Test001: Single PDN src NAT test					     */
+/* NOTE: other classes are derived from this class - change carefully        */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest001 : public IpaNatBlockTestFixture
+{
+public:
+	IpaNatBlockTest001()
+	{
+		m_name = "IpaNatBlockTest001";
+		m_description =
+			"NAT block test 001 - single PDN src NAT test\
+		1. Generate and commit three routing tables (only one is used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit one filtering rule: (DST & Mask Match). \
+			action go to src NAT \
+			All DST_IP == (193.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+		3. generate and commit one NAT rule:\
+			private ip 194.23.22.1 --> public ip 192.23.22.1";
+		m_private_ip = 0xC2171601; /* 194.23.22.1 */
+		m_private_port = 5678;
+		m_public_ip = 0xC0171601;   /* "192.23.22.1" */
+		m_public_port = 9050;
+		m_target_ip = 0xC1171601; /* 193.23.22.1 */
+		m_target_port = 1234;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering\n");
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0;
+
+		if (!CreateThreeIPv4BypassRoutingTables(bypass0, bypass1, bypass2))
+		{
+			LOG_MSG_ERROR("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n", &routing_table0);
+			return false;
+		}
+		LOG_MSG_DEBUG("%s route table handle = %u\n", bypass0, routing_table0.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4, IPA_CLIENT_TEST_PROD, false, 1);
+		LOG_MSG_DEBUG("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1, flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00FFFFFF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = m_target_ip; // Filter DST_IP == 193.23.22.1
+		flt_rule_entry.rule.pdn_idx = 0;
+		flt_rule_entry.rule.set_metadata = 0;
+		if (
+			((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR("Error Adding Rule to Filter Table, aborting...\n");
+			return false;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		//NAT table and rules creation
+		int total_entries = 20;
+		int ret;
+		ipa_nat_ipv4_rule ipv4_rule;
+
+		ret = ipa_nat_add_ipv4_tbl(m_public_ip, m_mem_type, total_entries, &m_tbl_hdl);
+		if (ret) {
+			LOG_MSG_DEBUG("failed creating NAT table\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("nat table added, hdl %d, public ip 0x%X\n", m_tbl_hdl,
+			m_public_ip);
+
+		ipv4_rule.target_ip = m_target_ip;
+		ipv4_rule.target_port = m_target_port;
+		ipv4_rule.private_ip = m_private_ip;
+		ipv4_rule.private_port = m_private_port;
+		ipv4_rule.protocol = IPPROTO_TCP;
+		ipv4_rule.public_port = m_public_port;
+		ipv4_rule.pdn_index = 0;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("failed adding NAT rule 0\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("NAT rule added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port);
+
+		LOG_MSG_DEBUG("Leaving");
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		uint32_t address;
+		uint16_t port;
+		char flags = 0x18;
+
+		address = htonl(m_target_ip);//193.23.22.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_target_port);
+		memcpy(&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = htonl(m_private_ip);/* 194.23.22.1 */
+		memcpy(&m_sendBuffer[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_private_port);
+		memcpy(&m_sendBuffer[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer[IPV4_TCP_FLAGS_OFFSET],&flags , sizeof(flags));
+		return true;
+	}// ModifyPacktes ()
+
+	virtual bool SendPackets()
+	{
+		bool isSuccess = false;
+
+		// Send first packet
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("sent successfully one packet\n");
+		return true;
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+
+		if (NULL == rxBuff1)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGoldenNat(
+			m_sendBuffer, m_sendSize,
+			rxBuff1, receivedSize,
+			m_private_ip, m_public_ip,
+			m_private_port, m_public_port,
+			true))
+		{
+			LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		char recievedBuffer[256] = { 0 };
+		char SentBuffer[256] = { 0 };
+		size_t j;
+
+		for (j = 0; j < m_sendSize; j++)
+			snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+		for (j = 0; j < receivedSize; j++)
+			snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+		LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+
+		delete[] rxBuff1;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test002: Single PDN dst NAT test					     */
+/* NOTE: other classes are derived from this class - change carefully        */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest002 : public IpaNatBlockTestFixture
+{
+public:
+	IpaNatBlockTest002()
+	{
+		m_name = "IpaNatBlockTest002";
+		m_description =
+			"NAT block test 002 - single PDN dst NAT test\
+		1. Generate and commit three routing tables (only one is used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit one filtering rule: (DST & Mask Match). \
+			action go to dst NAT \
+			All DST_IP == (192.23.22.1 & 0.255.255.255)traffic goes to NAT block (public IP filtering) \
+		3. generate and commit one NAT rule:\
+			public ip 192.23.22.1 --> private ip 194.23.22.1  ";
+		m_private_ip = 0xC2171601; /* 194.23.22.1 */
+		m_private_port = 5678;
+		m_public_ip = 0xC0171601;   /* "192.23.22.1" */
+		m_public_port = 9050;
+		m_target_ip = 0xC1171601; /* 193.23.22.1 */
+		m_target_port = 1234;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering\n");
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0;
+
+		if (!CreateThreeIPv4BypassRoutingTables(bypass0, bypass1, bypass2))
+		{
+			LOG_MSG_ERROR("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n", &routing_table0);
+			return false;
+		}
+		LOG_MSG_DEBUG("%s route table handle = %u\n", bypass0, routing_table0.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4, IPA_CLIENT_TEST_PROD, false, 3);
+		LOG_MSG_DEBUG("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1, flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00FFFFFF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = m_public_ip; // Filter DST_IP == 192.23.22.1
+		flt_rule_entry.rule.pdn_idx = 0;
+		flt_rule_entry.rule.set_metadata = 0;
+		if (
+			((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR("Error Adding Rule to Filter Table, aborting...\n");
+			return false;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		//NAT table and rules creation
+		int total_entries = 20;
+		int ret;
+		ipa_nat_ipv4_rule ipv4_rule;
+		uint32_t pub_ip_add = m_public_ip;
+
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, m_mem_type, total_entries, &m_tbl_hdl);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed creating NAT table\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("nat table added, hdl %d, public ip 0x%X\n", m_tbl_hdl,
+			pub_ip_add);
+
+		ipv4_rule.target_ip = m_target_ip;
+		ipv4_rule.target_port = m_target_port;
+		ipv4_rule.private_ip = m_private_ip;
+		ipv4_rule.private_port = m_private_port;
+		ipv4_rule.protocol = IPPROTO_TCP;
+		ipv4_rule.public_port = m_public_port;
+		ipv4_rule.pdn_index = 0;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 0\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("NAT rule added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port);
+
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		uint32_t address;
+		uint16_t port;
+		char flags = 0x18;
+
+		address = htonl(m_public_ip);//192.23.22.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_public_port);
+		memcpy(&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = htonl(m_target_ip);/* 193.23.22.1 */
+		memcpy(&m_sendBuffer[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_target_port);
+		memcpy(&m_sendBuffer[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer[IPV4_TCP_FLAGS_OFFSET], &flags, sizeof(flags));
+
+		return true;
+	}// ModifyPacktes ()
+
+	virtual bool SendPackets()
+	{
+		bool isSuccess = false;
+
+		// Send first packet
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("sent successfully one packet\n");
+		return true;
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+
+		if (NULL == rxBuff1)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGoldenNat(
+			m_sendBuffer, m_sendSize,
+			rxBuff1, receivedSize,
+			m_private_ip, m_public_ip,
+			m_private_port, m_public_port,
+			false))
+		{
+			LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		char recievedBuffer[256] = { 0 };
+		char SentBuffer[256] = { 0 };
+		size_t j;
+
+		for (j = 0; j < m_sendSize; j++)
+			snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+		for (j = 0; j < receivedSize; j++)
+			snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+		LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+
+		delete[] rxBuff1;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test003: Multi PDN src NAT test					     */
+/* NOTE: other classes are derived from this class - change carefully        */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest003 : public IpaNatBlockTestFixture
+{
+public:
+	IpaNatBlockTest003()
+	{
+		m_name = "IpaNatBlockTest003";
+		m_description =
+			"NAT block test 003 - Multi PDN src NAT test\
+		1. Generate and commit three routing tables (two are used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit two filtering rule: (DST & Mask Match). \
+			- action go to src NAT \
+			  All SRC_IP == (194.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+			  All SRC_IP == (197.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+		3. generate and commit two NAT rules:\
+			private ip 194.23.22.1 --> public ip 192.23.22.1 \
+			private ip 197.23.22.1 --> public ip 195.23.22.1";
+		m_private_ip = 0xC2171601; /* 194.23.22.1 */
+		m_private_port = 5678;
+		m_private_ip2 = 0xC5171601; /* 197.23.22.1 */
+		m_private_port2 = 5679;
+		m_public_ip = 0xC0171601;   /* "192.23.22.1" */
+		m_public_port = 9050;
+		m_public_ip2 = 0xC3171601;   /* "195.23.22.1" */
+		m_public_port2 = 9051;
+		m_target_ip = 0xC1171601; /* 193.23.22.1 */
+		m_target_port = 1234;
+		m_minIPAHwType = IPA_HW_v4_0;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering\n");
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0, routing_table1;
+
+		if (!CreateThreeIPv4BypassRoutingTables(bypass0, bypass1, bypass2))
+		{
+			LOG_MSG_ERROR("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n", &routing_table0);
+			return false;
+		}
+		LOG_MSG_DEBUG("%s route table handle = %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n", &routing_table1);
+			return false;
+		}
+		LOG_MSG_DEBUG("%s route table handle = %u\n", bypass1, routing_table1.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4, IPA_CLIENT_TEST_PROD, false, 2);
+		LOG_MSG_DEBUG("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1, flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_SRC_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.src_addr_mask = 0xFFFFFFFF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.src_addr = m_private_ip; // Filter SRC_IP == 194.23.22.1
+		flt_rule_entry.rule.pdn_idx = 0;
+		flt_rule_entry.rule.set_metadata = 0;
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			LOG_MSG_ERROR("Error Adding Rule to Filter Table, aborting...\n");
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.src_addr = m_private_ip2; // Filter SRC_IP == 197.23.22.1
+		if (
+			((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR("Error Adding Rule to Filter Table, aborting...\n");
+			return false;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(0)->status);
+			LOG_MSG_DEBUG("flt rule hdl1=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(1)->status);
+		}
+
+		//NAT table and rules creation
+		int total_entries = 20;
+		int ret;
+		ipa_nat_ipv4_rule ipv4_rule;
+		uint32_t pub_ip_add = m_public_ip;
+		ipa_nat_pdn_entry pdn_info;
+
+		// first create the NAT table
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, m_mem_type, total_entries, &m_tbl_hdl);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed creating NAT table\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("nat table added, hdl %d, public ip 0x%X\n", m_tbl_hdl,
+			pub_ip_add);
+
+		// modify the PDN entries that will be pointed by the NAT rules
+		pdn_info.public_ip = m_public_ip;
+		pdn_info.src_metadata = 0;
+		pdn_info.dst_metadata = 0;
+		ret = ipa_nat_modify_pdn(m_tbl_hdl, 0, &pdn_info);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed Modifying PDN entry 0 \n");
+			return false;
+		}
+
+		pdn_info.public_ip = m_public_ip2;
+		pdn_info.src_metadata = 0;
+		pdn_info.dst_metadata = 0;
+		ret = ipa_nat_modify_pdn(m_tbl_hdl, 1, &pdn_info);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed Modifying PDN entry 1 \n");
+			return false;
+		}
+
+		ipv4_rule.target_ip = m_target_ip;
+		ipv4_rule.target_port = m_target_port;
+		ipv4_rule.private_ip = m_private_ip;
+		ipv4_rule.private_port = m_private_port;
+		ipv4_rule.protocol = IPPROTO_TCP;
+		ipv4_rule.public_port = m_public_port;
+		ipv4_rule.pdn_index = 0;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 0\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("NAT rule added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port);
+
+		ipv4_rule.private_ip = m_private_ip2;
+		ipv4_rule.private_port = m_private_port2;
+		ipv4_rule.public_port = m_public_port2;
+		ipv4_rule.pdn_index = 1;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 1\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("NAT rule 2 added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port);
+
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		uint32_t address;
+		uint16_t port;
+		char flags = 0x18;
+
+		//first packet private ip 194.23.22.1 --> public ip 192.23.22.1
+		address = htonl(m_target_ip);//193.23.22.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_target_port);
+		memcpy(&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = htonl(m_private_ip);/* 194.23.22.1 */
+		memcpy(&m_sendBuffer[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_private_port);
+		memcpy(&m_sendBuffer[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer[IPV4_TCP_FLAGS_OFFSET], &flags, sizeof(flags));
+
+		// second packet private ip 197.23.22.1 --> public ip 195.23.22.1
+		address = htonl(m_target_ip);//193.23.22.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_target_port);
+		memcpy(&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = htonl(m_private_ip2);/* 197.23.22.1 */
+		memcpy(&m_sendBuffer2[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_private_port2);
+		memcpy(&m_sendBuffer2[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer2[IPV4_TCP_FLAGS_OFFSET], &flags, sizeof(flags));
+
+		return true;
+	}// ModifyPacktes ()
+
+	virtual bool SendPackets()
+	{
+		bool isSuccess = false;
+
+		// Send first packet
+		LOG_MSG_DEBUG("sending first packet\n");
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		LOG_MSG_DEBUG("sending second packet\n");
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("sent successfully two packets\n");
+		return true;
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+
+		if (rxBuff1 == NULL)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			if (rxBuff2)
+				delete[] rxBuff2;
+			return false;
+		}
+
+		if (rxBuff2 == NULL)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			delete[] rxBuff1;
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer2.ReceiveData(rxBuff2, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize2, m_consumer2.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGoldenNat(
+			m_sendBuffer, m_sendSize,
+			rxBuff1, receivedSize,
+			m_private_ip, m_public_ip,
+			m_private_port, m_public_port,
+			true))
+		{
+			LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		char recievedBuffer[256] = { 0 };
+		char SentBuffer[256] = { 0 };
+		char recievedBuffer2[256] = { 0 };
+		char SentBuffer2[256] = { 0 };
+		size_t j;
+
+		for (j = 0; j < m_sendSize; j++)
+			snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+		for (j = 0; j < receivedSize; j++)
+			snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+		LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+
+		delete[] rxBuff1;
+
+		isSuccess &= CompareResultVsGoldenNat(
+			m_sendBuffer2, m_sendSize2,
+			rxBuff2, receivedSize2,
+			m_private_ip2, m_public_ip2,
+			m_private_port2, m_public_port2,
+			true);
+
+		for (j = 0; j < m_sendSize2; j++)
+			snprintf(&SentBuffer2[3 * j], sizeof(SentBuffer2) - (3 * j + 1), " %02X", m_sendBuffer2[j]);
+		for (j = 0; j < receivedSize2; j++)
+			snprintf(&recievedBuffer2[3 * j], sizeof(recievedBuffer2) - (3 * j + 1), " %02X", rxBuff2[j]);
+		LOG_MSG_STACK("sent Value2 (%zu)\n%s\n, Received Value2(%zu)\n%s\n", m_sendSize2, SentBuffer2, receivedSize2, recievedBuffer2);
+
+		delete[] rxBuff2;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test004: Multi PDN dst NAT test					     */
+/* NOTE: other classes are derived from this class - change carefully        */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest004 : public IpaNatBlockTestFixture
+{
+public:
+	IpaNatBlockTest004()
+	{
+		m_name = "IpaNatBlockTest004";
+		m_description =
+			"NAT block test 004 - Multi PDN dst NAT test\
+		1. Generate and commit three routing tables (two are used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit two filtering rule: (DST & Mask Match). \
+			- action go to dst NAT \
+			  All DST_IP == (192.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+			  All DST_IP == (195.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+		3. generate and commit two NAT rules:\
+			private ip 194.23.22.1 --> public ip 192.23.22.1 \
+			private ip 197.23.22.1 --> public ip 195.23.22.1";
+		m_private_ip = 0xC2171601; /* 194.23.22.1 */
+		m_private_port = 5678;
+		m_private_ip2 = 0xC5171601; /* 197.23.22.1 */
+		m_private_port2 = 5679;
+		m_public_ip = 0xC0171601;   /* "192.23.22.1" */
+		m_public_port = 9050;
+		m_public_ip2 = 0xC3171601;   /* "195.23.22.1" */
+		m_public_port2 = 9051;
+		m_target_ip = 0xC1171601; /* 193.23.22.1 */
+		m_target_port = 1234;
+		m_minIPAHwType = IPA_HW_v4_0;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering\n");
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0, routing_table1;
+
+		if (!CreateThreeIPv4BypassRoutingTables(bypass0, bypass1, bypass2))
+		{
+			LOG_MSG_ERROR("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n", &routing_table0);
+			return false;
+		}
+		LOG_MSG_DEBUG("%s route table handle = %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n", &routing_table1);
+			return false;
+		}
+		LOG_MSG_DEBUG("%s route table handle = %u\n", bypass1, routing_table1.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4, IPA_CLIENT_TEST_PROD, false, 2);
+		LOG_MSG_DEBUG("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1, flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = m_public_ip; // Filter DST_IP == 192.23.22.1
+		flt_rule_entry.rule.pdn_idx = 0;
+		flt_rule_entry.rule.set_metadata = 0;
+		if ((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry))
+		{
+			LOG_MSG_ERROR("Error Adding Rule to Filter Table, aborting...\n");
+			return false;
+		}
+
+		// Configuring Filtering Rule No.1
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table1.hdl; //put here the handle corresponding to Routing Rule 2
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = m_public_ip2; // Filter DST_IP == 195.23.22.1
+		if (
+			((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR("Error Adding Rule to Filter Table, aborting...\n");
+			return false;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(0)->status);
+			LOG_MSG_DEBUG("flt rule hdl1=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(1)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(1)->status);
+		}
+
+		//NAT table and rules creation
+		int total_entries = 20;
+		int ret;
+		ipa_nat_ipv4_rule ipv4_rule;
+		uint32_t pub_ip_add = m_public_ip;
+		ipa_nat_pdn_entry pdn_info;
+
+		// first create the NAT table
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, m_mem_type, total_entries, &m_tbl_hdl);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed creating NAT table\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("nat table added, hdl %d, public ip 0x%X\n", m_tbl_hdl,
+			pub_ip_add);
+
+		// modify the PDN entries that will be pointed by the NAT rules
+		pdn_info.public_ip = m_public_ip;
+		pdn_info.src_metadata = 0;
+		pdn_info.dst_metadata = 0;
+		ret = ipa_nat_modify_pdn(m_tbl_hdl, 0,&pdn_info);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed Modifying PDN entry 0 \n");
+			return false;
+		}
+
+		pdn_info.public_ip = m_public_ip2;
+		pdn_info.src_metadata = 0;
+		pdn_info.dst_metadata = 0;
+		ret = ipa_nat_modify_pdn(m_tbl_hdl, 1, &pdn_info);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed Modifying PDN entry 1 \n");
+			return false;
+		}
+
+		ipv4_rule.target_ip = m_target_ip;
+		ipv4_rule.target_port = m_target_port;
+		ipv4_rule.private_ip = m_private_ip;
+		ipv4_rule.private_port = m_private_port;
+		ipv4_rule.protocol = IPPROTO_TCP;
+		ipv4_rule.public_port = m_public_port;
+		ipv4_rule.pdn_index = 0;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 0\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("NAT rule added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port);
+
+		ipv4_rule.private_ip = m_private_ip2;
+		ipv4_rule.private_port = m_private_port2;
+		ipv4_rule.public_port = m_public_port2;
+		ipv4_rule.pdn_index = 1;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 0\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("NAT rule 2 added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port);
+
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		uint32_t address;
+		uint16_t port;
+		char flags = 0x18;
+
+		//first packet private ip public ip 192.23.22.1 --> 194.23.22.1
+		address = htonl(m_public_ip);//192.23.22.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_public_port);
+		memcpy(&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = htonl(m_target_ip);/* 194.23.22.1 */
+		memcpy(&m_sendBuffer[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_target_port);
+		memcpy(&m_sendBuffer[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer[IPV4_TCP_FLAGS_OFFSET], &flags, sizeof(flags));
+
+		// second packet public ip 195.23.22.1--> private ip 197.23.22.1
+		address = htonl(m_public_ip2);//193.23.22.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_public_port2);
+		memcpy(&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = htonl(m_target_ip);/* 197.23.22.1 */
+		memcpy(&m_sendBuffer2[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_target_port);
+		memcpy(&m_sendBuffer2[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer2[IPV4_TCP_FLAGS_OFFSET], &flags, sizeof(flags));
+
+		return true;
+	}// ModifyPacktes ()
+
+	virtual bool SendPackets()
+	{
+		bool isSuccess = false;
+
+		// Send first packet
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("sent successfully two packets\n");
+		return true;
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+
+		if (rxBuff1 == NULL)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			if (rxBuff2)
+				delete[] rxBuff2;
+			return false;
+		}
+
+		if (rxBuff2 == NULL)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			delete[] rxBuff1;
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer2.ReceiveData(rxBuff2, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize2, m_consumer2.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGoldenNat(
+			m_sendBuffer, m_sendSize,
+			rxBuff1, receivedSize,
+			m_private_ip, m_public_ip,
+			m_private_port, m_public_port,
+			false))
+		{
+			LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		char recievedBuffer[256] = { 0 };
+		char SentBuffer[256] = { 0 };
+		char recievedBuffer2[256] = { 0 };
+		char SentBuffer2[256] = { 0 };
+		size_t j;
+
+		for (j = 0; j < m_sendSize; j++)
+			snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+		for (j = 0; j < receivedSize; j++)
+			snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+		LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+
+		delete[] rxBuff1;
+
+		isSuccess &= CompareResultVsGoldenNat(
+			m_sendBuffer2, m_sendSize2,
+			rxBuff2, receivedSize2,
+			m_private_ip2, m_public_ip2,
+			m_private_port2, m_public_port2,
+			false);
+
+		for (j = 0; j < m_sendSize2; j++)
+			snprintf(&SentBuffer2[3 * j], sizeof(SentBuffer2) - (3 * j + 1), " %02X", m_sendBuffer2[j]);
+		for (j = 0; j < receivedSize2; j++)
+			snprintf(&recievedBuffer2[3 * j], sizeof(recievedBuffer2) - (3 * j + 1), " %02X", rxBuff2[j]);
+		LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize2, SentBuffer2, receivedSize2, recievedBuffer2);
+
+		delete[] rxBuff2;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test005: Single PDN src metadata replacement NAT test		     */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest005 : public IpaNatBlockTestFixture
+{
+public:
+	IpaNatBlockTest005()
+	{
+		m_name = "IpaNatBlockTest005";
+		m_description =
+			"NAT block test 005 - single PDN src metadata replacement NAT test\
+			source metadata will be replaced and the routing rule equation will be done upon replaced value\
+		1. Generate and commit two routing tables (only one is used). \
+			the routing table will catch packets with metadata value 0x34567890 (different from original value)\
+		2. Generate and commit one filtering rule: (DST & Mask Match). \
+			action go to src NAT \
+			All DST_IP == (193.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+			action parameters metadata replacement = true\
+		3. generate and commit one NAT rule:\
+			private ip 194.23.22.1 --> public ip 192.23.22.1\
+			source metadata value shall be replaced to 0x34567890 (caught by the routing rule)";
+		m_private_ip = 0xC2171601; /* 194.23.22.1 */
+		m_private_port = 5678;
+		m_public_ip = 0xC0171601;   /* "192.23.22.1" */
+		m_public_port = 9050;
+		m_target_ip = 0xC1171601; /* 193.23.22.1 */
+		m_target_port = 1234;
+		m_metadata = 0x34567890;
+		m_minIPAHwType = IPA_HW_v4_0;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering\n");
+
+		const char bypass0[20] = "Bypass0";
+		struct ipa_ioc_get_rt_tbl routing_table0;
+
+		if (!CreateMetdataRoutingRule(bypass0))
+		{
+			LOG_MSG_ERROR("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("CreateMetdataRoutingRule completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n", &routing_table0);
+			return false;
+		}
+		LOG_MSG_DEBUG("%s route table handle = %u\n", bypass0, routing_table0.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4, IPA_CLIENT_TEST2_PROD, false, 1);
+		LOG_MSG_DEBUG("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1, flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = m_target_ip; // Filter DST_IP == 193.23.22.1
+		flt_rule_entry.rule.pdn_idx = 0;
+		flt_rule_entry.rule.set_metadata = 1;
+		flt_rule_entry.rule.retain_hdr = 1;
+		if (
+			((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR("Error Adding Rule to Filter Table, aborting...\n");
+			return false;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		//NAT table and rules creation
+		int total_entries = 20;
+		int ret;
+		ipa_nat_ipv4_rule ipv4_rule;
+		ipa_nat_pdn_entry pdn_info;
+
+		ret = ipa_nat_add_ipv4_tbl(m_public_ip, m_mem_type, total_entries, &m_tbl_hdl);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed creating NAT table\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("nat table added, hdl %d, public ip 0x%X\n", m_tbl_hdl,
+			m_public_ip);
+
+		ipv4_rule.target_ip = m_target_ip;
+		ipv4_rule.target_port = m_target_port;
+		ipv4_rule.private_ip = m_private_ip;
+		ipv4_rule.private_port = m_private_port;
+		ipv4_rule.protocol = IPPROTO_TCP;
+		ipv4_rule.public_port = m_public_port;
+		ipv4_rule.pdn_index = 0;
+
+		// modify the PDN entries that will be pointed by the NAT rules
+		pdn_info.public_ip = m_public_ip;
+		pdn_info.src_metadata = m_metadata;
+		pdn_info.dst_metadata = 0;
+		ret = ipa_nat_modify_pdn(m_tbl_hdl, 0, &pdn_info);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed modifying PDN index 0\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("PDN 0 was modified to hold ip 0x%X, src_metadata 0x%X\n", m_public_ip, m_metadata);
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 0\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("NAT rule added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port);
+
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		uint32_t address;
+		uint16_t port;
+		char flags = 0x18;
+
+		Load8021QPacket();
+
+		address = htonl(m_target_ip);//193.23.22.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET + ETH8021Q_HEADER_LEN], &address, sizeof(address));
+		port = htons(m_target_port);
+		memcpy(&m_sendBuffer[IPV4_DST_PORT_OFFSET + ETH8021Q_HEADER_LEN], &port, sizeof(port));
+
+		address = htonl(m_private_ip);/* 194.23.22.1 */
+		memcpy(&m_sendBuffer[IPV4_SRC_ADDR_OFFSET + ETH8021Q_HEADER_LEN], &address, sizeof(address));
+		port = htons(m_private_port);
+		memcpy(&m_sendBuffer[IPV4_SRC_PORT_OFFSET + ETH8021Q_HEADER_LEN], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer[IPV4_TCP_FLAGS_OFFSET + ETH8021Q_HEADER_LEN], &flags, sizeof(flags));
+		return true;
+	}// ModifyPacktes ()
+
+	virtual bool SendPackets()
+	{
+		bool isSuccess = false;
+
+		// Send first packet
+		isSuccess = m_producer2.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("sent successfully one packet\n");
+		return true;
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+
+		if (NULL == rxBuff1)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGoldenNat(
+			m_sendBuffer, m_sendSize,
+			rxBuff1, receivedSize,
+			m_private_ip, m_public_ip,
+			m_private_port, m_public_port,
+			true, ETH8021Q_HEADER_LEN))
+		{
+			LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		char recievedBuffer[256] = { 0 };
+		char SentBuffer[256] = { 0 };
+		size_t j;
+
+		for (j = 0; j < m_sendSize; j++)
+			snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+		for (j = 0; j < receivedSize; j++)
+			snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+		LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+
+		delete[] rxBuff1;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test006: Single PDN dst metadata replacement NAT test		     */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest006 : public IpaNatBlockTestFixture
+{
+public:
+	IpaNatBlockTest006()
+	{
+		m_name = "IpaNatBlockTest006";
+		m_description =
+			"NAT block test 006 - single PDN dst metadata replacement NAT test\
+			destination metadata will be replaced and the routing rule equation will be done upon replaced value\
+		1. Generate and commit two routing tables (only one is used). \
+			the routing table will catch packets with metadata value 0x34567890 (different from original value)\
+		2. Generate and commit one filtering rule: (DST & Mask Match). \
+			action go to dst NAT \
+			All DST_IP == (192.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+			action parameters metadata replacement = true\
+		3. generate and commit one NAT rule:\
+			public ip 192.23.22.1 --> private ip 194.23.22.1 \
+			destination metadata value shall be replaced to 0x34567890 (caught by the routing rule)";
+		m_private_ip = 0xC2171601; /* 194.23.22.1 */
+		m_private_port = 5678;
+		m_public_ip = 0xC0171601;   /* "192.23.22.1" */
+		m_public_port = 9050;
+		m_target_ip = 0xC1171601; /* 193.23.22.1 */
+		m_target_port = 1234;
+		m_metadata = 0x34567890;
+		m_minIPAHwType = IPA_HW_v4_0;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering\n");
+
+		const char bypass0[20] = "Bypass0";
+		struct ipa_ioc_get_rt_tbl routing_table0;
+
+		if (!CreateMetdataRoutingRule(bypass0))
+		{
+			LOG_MSG_ERROR("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("CreateMetdataRoutingRule completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n", &routing_table0);
+			return false;
+		}
+		LOG_MSG_DEBUG("%s route table handle = %u\n", bypass0, routing_table0.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4, IPA_CLIENT_TEST2_PROD, false, 1);
+		LOG_MSG_DEBUG("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1, flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = m_public_ip; // Filter DST_IP == 193.23.22.1
+		flt_rule_entry.rule.pdn_idx = 0;
+		flt_rule_entry.rule.set_metadata = 1;
+		flt_rule_entry.rule.retain_hdr = 1;
+		if (
+			((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR("Error Adding Rule to Filter Table, aborting...\n");
+			return false;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		//NAT table and rules creation
+		int total_entries = 20;
+		int ret;
+		ipa_nat_ipv4_rule ipv4_rule;
+		ipa_nat_pdn_entry pdn_info;
+
+		ret = ipa_nat_add_ipv4_tbl(m_public_ip, m_mem_type, total_entries, &m_tbl_hdl);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed creating NAT table\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("nat table added, hdl %d, public ip 0x%X\n", m_tbl_hdl,
+			m_public_ip);
+
+		ipv4_rule.target_ip = m_target_ip;
+		ipv4_rule.target_port = m_target_port;
+		ipv4_rule.private_ip = m_private_ip;
+		ipv4_rule.private_port = m_private_port;
+		ipv4_rule.protocol = IPPROTO_TCP;
+		ipv4_rule.public_port = m_public_port;
+		ipv4_rule.pdn_index = 0;
+
+		// modify the PDN entries that will be pointed by the NAT rules
+		pdn_info.public_ip = m_public_ip;
+		pdn_info.src_metadata = 0;
+		pdn_info.dst_metadata = m_metadata;
+		ret = ipa_nat_modify_pdn(m_tbl_hdl, 0, &pdn_info);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed modifying PDN index 0\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("PDN 0 was modified to hold ip 0x%X, dst_metadata 0x%X\n", m_public_ip, m_metadata);
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 0\n");
+			return false;
+		}
+		LOG_MSG_ERROR("NAT rule added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port);
+
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		uint32_t address;
+		uint16_t port;
+		char flags = 0x18;
+
+		Load8021QPacket();
+
+		address = htonl(m_public_ip);//193.23.22.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET + ETH8021Q_HEADER_LEN], &address, sizeof(address));
+		port = htons(m_public_port);
+		memcpy(&m_sendBuffer[IPV4_DST_PORT_OFFSET + ETH8021Q_HEADER_LEN], &port, sizeof(port));
+
+		address = htonl(m_target_ip);/* 194.23.22.1 */
+		memcpy(&m_sendBuffer[IPV4_SRC_ADDR_OFFSET + ETH8021Q_HEADER_LEN], &address, sizeof(address));
+		port = htons(m_target_port);
+		memcpy(&m_sendBuffer[IPV4_SRC_PORT_OFFSET + ETH8021Q_HEADER_LEN], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer[IPV4_TCP_FLAGS_OFFSET + ETH8021Q_HEADER_LEN], &flags, sizeof(flags));
+		return true;
+	}// ModifyPacktes ()
+
+	virtual bool SendPackets()
+	{
+		bool isSuccess = false;
+
+		// Send first packet
+		isSuccess = m_producer2.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("sent successfully one packet\n");
+		return true;
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+
+		if (NULL == rxBuff1)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGoldenNat(
+			m_sendBuffer, m_sendSize,
+			rxBuff1, receivedSize,
+			m_private_ip, m_public_ip,
+			m_private_port, m_public_port,
+			false, ETH8021Q_HEADER_LEN))
+		{
+			LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		char recievedBuffer[256] = { 0 };
+		char SentBuffer[256] = { 0 };
+		size_t j;
+
+		for (j = 0; j < m_sendSize; j++)
+			snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+		for (j = 0; j < receivedSize; j++)
+			snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+		LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+
+		delete[] rxBuff1;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test007: Hashable routing rule with dst NAT test                          */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest007 : public IpaNatBlockTestFixture
+{
+public:
+	IpaNatBlockTest007()
+	{
+		m_name = "IpaNatBlockTest007";
+		m_description =
+			"NAT block test 007 - single PDN dst NAT with hashable routing rule test\
+			test if routing block hash mechanism tests NATed values or pre NAT values\
+		1. Generate and commit routing table with two hashable rules. \
+			first routing rule will send packets with ip == 192.168.9.119 to first pipe \
+			second routing rule will send packets with ip == 192.168.9.120 to second pipe\
+		2. Generate and commit one filtering rule: (DST & Mask Match). \
+			action go to dst NAT \
+			All DST_IP == (192.168.9.1 & 255.255.255.0)traffic goes to NAT block \
+		3. generate and commit two NAT rules with target ip 211.1.1.4:\
+			1. public ip 5.5.6.120 --> private ip 192.168.9.119 \
+			   public port 4501 --> private port 4500 \
+			2.  public ip 5.5.6.120 --> private ip 192.168.9.119 \
+			    public port 4502 --> private port 4500";
+		m_private_ip = 0xC0A80977; /* 192.168.9.119 */
+		m_private_port = 4500;
+		m_private_ip2 = 0xC0A80978; /* 192.168.9.120 */
+		m_private_port2 = 4500;
+		m_public_ip = 0x05050678;   /* 5.5.6.120 */
+		m_public_port = 4501;
+		m_public_port2 = 4502;
+		m_target_ip = 0xD3010104; /* 211.1.1.4 */
+		m_target_port = 1234;
+		m_minIPAHwType = IPA_HW_v4_0;
+		Register(*this);
+	}
+
+	bool Setup()
+	{
+		return IpaNatBlockTestFixture::Setup(true);
+	}
+
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering\n");
+
+		const char bypass0[20] = "Bypass0";
+		struct ipa_ioc_get_rt_tbl routing_table0;
+
+		if (!CreateHashableRoutingRules(bypass0))
+		{
+			LOG_MSG_ERROR("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("CreateHashableRoutingRules completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n", &routing_table0);
+			return false;
+		}
+		LOG_MSG_DEBUG("%s route table handle = %u\n", bypass0, routing_table0.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4, IPA_CLIENT_TEST_PROD, false, 1);
+		LOG_MSG_DEBUG("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1, flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl; //put here the handle corresponding to Routing table 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000; // Mask - catch all
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = m_public_ip; // Filter DST_IP == 5.5.6.120
+		flt_rule_entry.rule.pdn_idx = 0;
+		flt_rule_entry.rule.set_metadata = 0;
+		if (
+			((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR("Error Adding Rule to Filter Table, aborting...\n");
+			return false;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		//NAT table and rules creation
+		int total_entries = 20;
+		int ret;
+		ipa_nat_ipv4_rule ipv4_rule;
+
+		ret = ipa_nat_add_ipv4_tbl(m_public_ip, m_mem_type, total_entries, &m_tbl_hdl);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed creating NAT table\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("nat table added, hdl %d, public ip 0x%X\n", m_tbl_hdl,
+			m_public_ip);
+
+		ipv4_rule.target_ip = m_target_ip;
+		ipv4_rule.target_port = m_target_port;
+		ipv4_rule.private_ip = m_private_ip;
+		ipv4_rule.private_port = m_private_port;
+		ipv4_rule.protocol = IPPROTO_TCP;
+		ipv4_rule.public_port = m_public_port;
+		ipv4_rule.pdn_index = 0;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 0\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("NAT rule 1 added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port);
+
+		ipv4_rule.target_ip = m_target_ip;
+		ipv4_rule.target_port = m_target_port;
+		ipv4_rule.private_ip = m_private_ip2;
+		ipv4_rule.private_port = m_private_port2;
+		ipv4_rule.protocol = IPPROTO_TCP;
+		ipv4_rule.public_port = m_public_port2;
+		ipv4_rule.pdn_index = 0;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 0\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("NAT rule 2 added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port);
+
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		uint32_t address;
+		uint16_t port;
+		char flags = 0x18;
+
+		address = ntohl(m_public_ip);//5.5.6.120
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = ntohs(m_public_port); // 4501
+		memcpy(&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = ntohl(m_target_ip);/* 211.1.1.4 */
+		memcpy(&m_sendBuffer[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		port = ntohs(m_target_port); // 4500
+		memcpy(&m_sendBuffer[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer[IPV4_TCP_FLAGS_OFFSET], &flags, sizeof(flags));
+
+		// second packet
+		address = ntohl(m_public_ip);//5.5.6.120
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = ntohs(m_public_port2); // 4502
+		memcpy(&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = ntohl(m_target_ip);/* 211.1.1.4 */
+		memcpy(&m_sendBuffer2[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		port = ntohs(m_target_port); // 4500
+		memcpy(&m_sendBuffer2[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer2[IPV4_TCP_FLAGS_OFFSET], &flags, sizeof(flags));
+		return true;
+	}// ModifyPacktes ()
+
+	virtual bool SendPackets()
+	{
+		bool isSuccess = false;
+
+		// Send first packet
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("sent successfully the first packet\n");
+
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("sent successfully two packet\n");
+		return true;
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+
+		if (rxBuff1 == NULL || rxBuff2 == NULL)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer2.ReceiveData(rxBuff2, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize2, m_consumer2.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGoldenNat(
+			m_sendBuffer, m_sendSize,
+			rxBuff1, receivedSize,
+			m_private_ip, m_public_ip,
+			m_private_port, m_public_port,
+			false, 0, true))
+		{
+			LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize, receivedSize, rxBuff1) : IsCacheMiss(m_sendSize, receivedSize, rxBuff1);
+
+		char recievedBuffer[0x400] = { 0 };
+		char SentBuffer[0x400] = { 0 };
+		char recievedBuffer2[0x400] = { 0 };
+		char SentBuffer2[0x400] = { 0 };
+		size_t j;
+
+		for (j = 0; j < m_sendSize; j++)
+			snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+		for (j = 0; j < receivedSize; j++)
+			snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+		LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+
+		delete[] rxBuff1;
+
+		isSuccess &= CompareResultVsGoldenNat(
+			m_sendBuffer2, m_sendSize2,
+			rxBuff2, receivedSize2,
+			m_private_ip2, m_public_ip,
+			m_private_port2, m_public_port2,
+			false, 0, true);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize2, receivedSize2, rxBuff2) : IsCacheMiss(m_sendSize2, receivedSize2, rxBuff2);
+
+		for (j = 0; j < m_sendSize2; j++)
+			snprintf(&SentBuffer2[3 * j], sizeof(SentBuffer2) - (3 * j + 1), " %02X", m_sendBuffer2[j]);
+		for (j = 0; j < receivedSize2; j++)
+			snprintf(&recievedBuffer2[3 * j], sizeof(recievedBuffer2) - (3 * j + 1), " %02X", rxBuff2[j]);
+		LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize2, SentBuffer2, receivedSize2, recievedBuffer2);
+
+		delete[] rxBuff2;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test008: Multi PDN src NAT test match PDN by input from filtering block   */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest008 : public IpaNatBlockTestFixture
+{
+public:
+	IpaNatBlockTest008()
+	{
+		m_name = "IpaNatBlockTest008";
+		m_description =
+			"NAT block test 008 - Multi PDN src NAT test match PDN by input from filtering block\
+		1. Generate and commit three routing tables (two are used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit one filtering rule: (DST & Mask Match). \
+			- action go to src NAT + PDN index 2\
+			  All SRC_IP == (194.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+		3. generate and commit two NAT rules:\
+			private ip 194.23.22.1 --> public ip 192.23.22.1 PDN index 1\
+			private ip 194.23.22.1 --> public ip 195.23.22.1 PDN index 2";
+		m_private_ip = 0xC2171601; /* 194.23.22.1 */
+		m_private_port = 5678;
+		m_public_ip = 0xC0171601;   /* "192.23.22.1" */
+		m_public_port = 9050;
+		m_public_ip2 = 0xC3171601;   /* "195.23.22.1" */
+		m_target_ip = 0xC1171601; /* 193.23.22.1 */
+		m_target_port = 1234;
+		m_minIPAHwType = IPA_HW_v4_0;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering\n");
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0, routing_table1;
+
+		if (!CreateThreeIPv4BypassRoutingTables(bypass0, bypass1, bypass2))
+		{
+			LOG_MSG_ERROR("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n", &routing_table0);
+			return false;
+		}
+		LOG_MSG_DEBUG("%s route table handle = %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n", &routing_table1);
+			return false;
+		}
+		LOG_MSG_DEBUG("%s route table handle = %u\n", bypass1, routing_table1.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4, IPA_CLIENT_TEST_PROD, false, 2);
+		LOG_MSG_DEBUG("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1, flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl; //put here the handle corresponding to Routing Rule 1
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_SRC_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.src_addr_mask = 0xFFFFFFFF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.src_addr = m_private_ip; // Filter SRC_IP == 194.23.22.1
+		flt_rule_entry.rule.pdn_idx = 2;
+		flt_rule_entry.rule.set_metadata = 0;
+		if (
+			((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR("Error Adding Rule to Filter Table, aborting...\n");
+			return false;
+		}
+		else
+		{
+			LOG_MSG_ERROR("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		//NAT table and rules creation
+		int total_entries = 20;
+		int ret;
+		ipa_nat_ipv4_rule ipv4_rule;
+		uint32_t pub_ip_add = m_public_ip;
+		ipa_nat_pdn_entry pdn_info;
+
+		// first create the NAT table
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, m_mem_type, total_entries, &m_tbl_hdl);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed creating NAT table\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("nat table added, hdl %d, public ip 0x%X\n", m_tbl_hdl,
+			pub_ip_add);
+
+		// modify the PDN entries that will be pointed by the NAT rules
+		pdn_info.public_ip = m_public_ip;
+		pdn_info.src_metadata = 0;
+		pdn_info.dst_metadata = 0;
+		ret = ipa_nat_modify_pdn(m_tbl_hdl, 1, &pdn_info);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed Modifying PDN entry 0 \n");
+			return false;
+		}
+
+		pdn_info.public_ip = m_public_ip2;
+		pdn_info.src_metadata = 0;
+		pdn_info.dst_metadata = 0;
+		ret = ipa_nat_modify_pdn(m_tbl_hdl, 2, &pdn_info);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed Modifying PDN entry 1 \n");
+			return false;
+		}
+
+		ipv4_rule.target_ip = m_target_ip;
+		ipv4_rule.target_port = m_target_port;
+		ipv4_rule.private_ip = m_private_ip;
+		ipv4_rule.private_port = m_private_port;
+		ipv4_rule.protocol = IPPROTO_TCP;
+		ipv4_rule.public_port = m_public_port;
+		ipv4_rule.pdn_index = 1;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 0\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("NAT rule added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port);
+
+		// the second rule shall be identical to the first on all parameters except PDN index so the filtering
+		// block action parameter will provide the PDN index.
+		ipv4_rule.pdn_index = 2;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 1\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("NAT rule 2 added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port);
+
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		uint32_t address;
+		uint16_t port;
+		char flags = 0x18;
+
+		//first packet private ip 194.23.22.1 --> public ip 195.23.22.1
+		address = htonl(m_target_ip);//193.23.22.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_target_port);
+		memcpy(&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = htonl(m_private_ip);/* 194.23.22.1 */
+		memcpy(&m_sendBuffer[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_private_port);
+		memcpy(&m_sendBuffer[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer[IPV4_TCP_FLAGS_OFFSET], &flags, sizeof(flags));
+
+		return true;
+	}// ModifyPacktes ()
+
+	virtual bool SendPackets()
+	{
+		bool isSuccess = false;
+
+		// Send first packet
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+		return true;
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+
+		if (rxBuff1 == NULL)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		// Compare results - verify that the ip of PDN 2 was selected (m_public_ip2)
+		if (!CompareResultVsGoldenNat(
+			m_sendBuffer, m_sendSize,
+			rxBuff1, receivedSize,
+			m_private_ip, m_public_ip2,
+			m_private_port, m_public_port,
+			true))
+		{
+			LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		char recievedBuffer[256] = { 0 };
+		char SentBuffer[256] = { 0 };
+		size_t j;
+
+		for (j = 0; j < m_sendSize; j++)
+			snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+		for (j = 0; j < receivedSize; j++)
+			snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+		LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+
+		delete[] rxBuff1;
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test009: Single PDN src NAT delete rule test                              */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest009 : public IpaNatBlockTest001
+{
+public:
+	IpaNatBlockTest009()
+	{
+		m_name = "IpaNatBlockTest009";
+		m_description =
+			"NAT block test 009 - single PDN src NAT rule deletion test\
+		1. Generate and commit three routing tables (only one is used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit one filtering rule: (DST & Mask Match). \
+			action go to src NAT \
+			All DST_IP == (193.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+		3. generate and commit one NAT rule:\
+			private ip 194.23.22.1 --> public ip 192.23.22.1\
+		4. delete the NAT rule and expect NAT miss";
+	}
+
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering\n");
+
+		int ret = IpaNatBlockTest001::AddRules();
+		if (!ret) {
+			LOG_MSG_ERROR("Leaving, failed Adding test 001 rules 0\n");
+			return false;
+		}
+
+		ret = ipa_nat_del_ipv4_rule(m_tbl_hdl, m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed deleting NAT rule 0\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("NAT rule deleted\n");
+
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}// AddRules()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+
+		if (NULL == rxBuff1)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		if (receivedSize) {
+			LOG_MSG_ERROR("Data received - test failed!\n");
+			isSuccess = false;
+
+			// Compare results
+			if (!CompareResultVsGoldenNat(
+				m_sendBuffer, m_sendSize,
+				rxBuff1, receivedSize,
+				m_private_ip, m_public_ip,
+				m_private_port, m_public_port,
+				true))
+			{
+				LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			} else {
+				LOG_MSG_ERROR("Comparison of Buffer0 succeeded - NAT rule was hit despite deletion!\n");
+			}
+
+			char recievedBuffer[256] = { 0 };
+			char SentBuffer[256] = { 0 };
+			size_t j;
+
+			for (j = 0; j < m_sendSize; j++)
+				snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+			for (j = 0; j < receivedSize; j++)
+				snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+			LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+		}
+
+		delete[] rxBuff1;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test010: Single PDN dst NAT rule deletion test                            */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest010 : public IpaNatBlockTest002
+{
+public:
+	IpaNatBlockTest010()
+	{
+		m_name = "IpaNatBlockTest010";
+		m_description =
+			"NAT block test 010 - single PDN dst NAT rule deletion test\
+		1. Generate and commit three routing tables (only one is used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit one filtering rule: (DST & Mask Match). \
+			action go to dst NAT \
+			All DST_IP == (192.23.22.1 & 0.255.255.255)traffic goes to NAT block (public IP filtering) \
+		3. generate and commit one NAT rule:\
+			public ip 192.23.22.1 --> private ip 194.23.22.1  \
+			delete rule and verrify NAT miss";
+	}
+
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering\n");
+
+		int ret = IpaNatBlockTest002::AddRules();
+		if (!ret) {
+			LOG_MSG_ERROR("Leaving, failed Adding test 002 rules 0\n");
+			return false;
+		}
+
+		ret = ipa_nat_del_ipv4_rule(m_tbl_hdl, m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed deleting NAT rule 0\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("NAT rule deleted\n");
+
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}// AddRules()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+
+		if (NULL == rxBuff1)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		if (receivedSize) {
+			LOG_MSG_ERROR("Data received - test failed!\n");
+			isSuccess = false;
+
+			// Compare results
+			if (!CompareResultVsGoldenNat(
+				m_sendBuffer, m_sendSize,
+				rxBuff1, receivedSize,
+				m_private_ip, m_public_ip,
+				m_private_port, m_public_port,
+				false))
+			{
+				LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			}
+			else {
+				LOG_MSG_ERROR("Comparison of Buffer0 succeeded - NAT rule was hit despite deletion!\n");
+			}
+
+			char recievedBuffer[256] = { 0 };
+			char SentBuffer[256] = { 0 };
+			size_t j;
+
+			for (j = 0; j < m_sendSize; j++)
+				snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+			for (j = 0; j < receivedSize; j++)
+				snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+			LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+		}
+
+		delete[] rxBuff1;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test011: Multi PDN src NAT - MAX number of PDNs test                      */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest011 : public IpaNatBlockTestFixture
+{
+	uint32_t m_public_ip3;
+	uint32_t m_public_ip4;
+	uint32_t m_private_ip3;
+	uint32_t m_private_ip4;
+	uint16_t m_public_port3;
+	uint16_t m_public_port4;
+	uint16_t m_private_port3;
+	uint16_t m_private_port4;
+	Byte m_sendBuffer4[BUFF_MAX_SIZE];
+	size_t m_sendSize4;
+
+public:
+	IpaNatBlockTest011()
+	{
+		m_name = "IpaNatBlockTest011";
+		m_description =
+			"NAT block test 011 - Multi PDN src NAT test\
+		1. Generate and commit three routing tables (one is used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit one filtering rule: (DST & Mask Match). \
+			- action go to src NAT \
+			  All SRC_IP == (192.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+			  All SRC_IP == (194.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+			  All SRC_IP == (196.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+			  All SRC_IP == (198.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+		3. generate and commit four NAT rules:\
+			private ip 192.23.22.1 --> public ip 193.23.22.1 \
+			private ip 194.23.22.1 --> public ip 195.23.22.1 \
+			private ip 196.23.22.1 --> public ip 197.23.22.1 \
+			private ip 198.23.22.1 --> public ip 199.23.22.1";
+		m_private_ip = 0xC0171601; /* 192.23.22.1 */
+		m_private_port = 5678;
+		m_public_ip = 0xC1171601;   /* "193.23.22.1" */
+		m_public_port = 9050;
+
+		m_private_ip2 = 0xC2171601; /* 194.23.22.1 */
+		m_private_port2 = 5679;
+		m_public_ip2 = 0xC3171601;   /* "195.23.22.1" */
+		m_public_port2 = 9051;
+
+		m_private_ip3 = 0xC4171601; /* 196.23.22.1 */
+		m_private_port3 = 5680;
+		m_public_ip3 = 0xC5171601;   /* "197.23.22.1" */
+		m_public_port3 = 9052;
+
+		m_private_ip4 = 0xC6171601; /* 198.23.22.1 */
+		m_private_port4 = 5681;
+		m_public_ip4 = 0xC7171601;   /* "199.23.22.1" */
+		m_public_port4 = 9053;
+
+		m_target_ip = 0xBF171601; /* 191.23.22.1 */
+		m_target_port = 1234;
+
+		m_sendSize4 = BUFF_MAX_SIZE;
+		m_minIPAHwType = IPA_HW_v4_0;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering\n");
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0, routing_table1;
+
+		if (!CreateThreeIPv4BypassRoutingTables(bypass0, bypass1, bypass2))
+		{
+			LOG_MSG_ERROR("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n", &routing_table0);
+			return false;
+		}
+		LOG_MSG_DEBUG("%s route table handle = %u\n", bypass0, routing_table0.hdl);
+
+		routing_table1.ip = IPA_IP_v4;
+		strlcpy(routing_table1.name, bypass1, sizeof(routing_table1.name));
+		if (!m_routing.GetRoutingTable(&routing_table1))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table1=0x%p) Failed.\n", &routing_table1);
+			return false;
+		}
+		LOG_MSG_DEBUG("%s route table handle = %u\n", bypass1, routing_table1.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4, IPA_CLIENT_TEST_PROD, false, 1);
+		LOG_MSG_DEBUG("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1, flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_SRC_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.src_addr_mask = 0x00FFFFFF; // Mask - catch all private IPs
+		flt_rule_entry.rule.attrib.u.v4.src_addr = m_private_ip; // Filter SRC_IP == 192.23.22.1
+		flt_rule_entry.rule.pdn_idx = 0;
+		flt_rule_entry.rule.set_metadata = 0;
+		if (
+			((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR("Error Adding Rule to Filter Table, aborting...\n");
+			return false;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		//NAT table and rules creation
+		int total_entries = 20;
+		int ret;
+		ipa_nat_ipv4_rule ipv4_rule;
+		ipa_nat_pdn_entry pdn_info;
+
+		// first create the NAT table
+		ret = ipa_nat_add_ipv4_tbl(m_public_ip, m_mem_type, total_entries, &m_tbl_hdl);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed creating NAT table\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("nat table added, hdl %d, public ip 0x%X\n", m_tbl_hdl,
+			m_public_ip);
+
+		// modify the PDN entries that will be pointed by the NAT rules
+		pdn_info.public_ip = m_public_ip;
+		pdn_info.src_metadata = 0;
+		pdn_info.dst_metadata = 0;
+		ret = ipa_nat_modify_pdn(m_tbl_hdl, 0, &pdn_info);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed Modifying PDN entry 0 \n");
+			return false;
+		}
+
+		pdn_info.public_ip = m_public_ip2;
+		ret = ipa_nat_modify_pdn(m_tbl_hdl, 1, &pdn_info);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed Modifying PDN entry 1 \n");
+			return false;
+		}
+
+		pdn_info.public_ip = m_public_ip3;
+		ret = ipa_nat_modify_pdn(m_tbl_hdl, 2, &pdn_info);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed Modifying PDN entry 2 \n");
+			return false;
+		}
+
+		pdn_info.public_ip = m_public_ip4;
+		ret = ipa_nat_modify_pdn(m_tbl_hdl, 3, &pdn_info);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed Modifying PDN entry 3 \n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("Added 4 PDNs successfully: 0x%X, 0x%X, 0x%X, 0x%X\n",
+			m_public_ip, m_public_ip2, m_public_ip3, m_public_ip4);
+
+		ipv4_rule.target_ip = m_target_ip;
+		ipv4_rule.target_port = m_target_port;
+		ipv4_rule.private_ip = m_private_ip;
+		ipv4_rule.private_port = m_private_port;
+		ipv4_rule.protocol = IPPROTO_TCP;
+		ipv4_rule.public_port = m_public_port;
+		ipv4_rule.pdn_index = 0;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 0\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("NAT rule added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d, $d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port, ipv4_rule.pdn_index);
+
+		ipv4_rule.private_ip = m_private_ip2;
+		ipv4_rule.private_port = m_private_port2;
+		ipv4_rule.public_port = m_public_port2;
+		ipv4_rule.pdn_index = 1;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 1\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("NAT rule 2 added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d, $d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port, ipv4_rule.pdn_index);
+
+		ipv4_rule.private_ip = m_private_ip3;
+		ipv4_rule.private_port = m_private_port3;
+		ipv4_rule.public_port = m_public_port3;
+		ipv4_rule.pdn_index = 2;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 2\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("NAT rule 3 added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d, $d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port, ipv4_rule.pdn_index);
+
+		ipv4_rule.private_ip = m_private_ip4;
+		ipv4_rule.private_port = m_private_port4;
+		ipv4_rule.public_port = m_public_port4;
+		ipv4_rule.pdn_index = 3;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 3\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("NAT rule 4 added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d, $d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port, ipv4_rule.pdn_index);
+
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		uint32_t address;
+		uint16_t port;
+		char flags = 0x18;
+
+		if (!LoadDefaultPacket(IPA_IP_v4, m_extHdrType, m_sendBuffer4, m_sendSize4)) {
+			LOG_MSG_ERROR("Failed default Packet buffer 4\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("Loaded %zu Bytes to Buffer 4\n", m_sendSize4);
+
+		//first packet private ip 192.23.22.1 --> public ip 193.23.22.1
+		address = htonl(m_target_ip);//191.23.22.1
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_target_port);
+		memcpy(&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = htonl(m_private_ip);/* 192.23.22.1 */
+		memcpy(&m_sendBuffer[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_private_port);
+		memcpy(&m_sendBuffer[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer[IPV4_TCP_FLAGS_OFFSET], &flags, sizeof(flags));
+
+		// second packet private ip 194.23.22.1 --> public ip 195.23.22.1
+		address = htonl(m_target_ip);//191.23.22.1
+		memcpy(&m_sendBuffer2[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_target_port);
+		memcpy(&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = htonl(m_private_ip2);/* 194.23.22.1 */
+		memcpy(&m_sendBuffer2[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_private_port2);
+		memcpy(&m_sendBuffer2[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer2[IPV4_TCP_FLAGS_OFFSET], &flags, sizeof(flags));
+
+		// third packet private ip 196.23.22.1 --> public ip 197.23.22.1
+		address = htonl(m_target_ip);//191.23.22.1
+		memcpy(&m_sendBuffer3[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_target_port);
+		memcpy(&m_sendBuffer3[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = htonl(m_private_ip3);/* 196.23.22.1 */
+		memcpy(&m_sendBuffer3[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_private_port3);
+		memcpy(&m_sendBuffer3[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer3[IPV4_TCP_FLAGS_OFFSET], &flags, sizeof(flags));
+
+		// third packet private ip 198.23.22.1 --> public ip 199.23.22.1
+		address = htonl(m_target_ip);//191.23.22.1
+		memcpy(&m_sendBuffer4[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_target_port);
+		memcpy(&m_sendBuffer4[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = htonl(m_private_ip4);/* 198.23.22.1 */
+		memcpy(&m_sendBuffer4[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_private_port4);
+		memcpy(&m_sendBuffer4[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer4[IPV4_TCP_FLAGS_OFFSET], &flags, sizeof(flags));
+
+		return true;
+	}// ModifyPacktes ()
+
+	virtual bool SendPackets()
+	{
+		bool isSuccess = false;
+
+		// Send first packet
+		LOG_MSG_DEBUG("sending first packet\n");
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		LOG_MSG_DEBUG("sending second packet\n");
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		LOG_MSG_DEBUG("sending third packet\n");
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		// Send fourth packet
+		LOG_MSG_DEBUG("sending fourth packet\n");
+		isSuccess = m_producer.SendData(m_sendBuffer4, m_sendSize4);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("sent successfully four packets\n");
+		return true;
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		size_t receivedSize4 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+		Byte *rxBuff4 = new Byte[0x400];
+
+		if (rxBuff1 == NULL)
+		{
+			LOG_MSG_ERROR("Memory allocation error 1.\n");
+			if (rxBuff2)
+				delete[] rxBuff2;
+			if (rxBuff3)
+				delete[] rxBuff3;
+			if (rxBuff4)
+				delete[] rxBuff4;
+			return false;
+		}
+
+		if (rxBuff2 == NULL)
+		{
+			LOG_MSG_ERROR("Memory allocation error 2.\n");
+			delete[] rxBuff1;
+			if (rxBuff3)
+				delete[] rxBuff3;
+			if (rxBuff4)
+				delete[] rxBuff4;
+			return false;
+		}
+
+		if (rxBuff3 == NULL)
+		{
+			LOG_MSG_ERROR("Memory allocation error 3.\n");
+			delete[] rxBuff1;
+			delete[] rxBuff2;
+			if (rxBuff4)
+				delete[] rxBuff4;
+			return false;
+		}
+
+		if (rxBuff4 == NULL)
+		{
+			LOG_MSG_ERROR("Memory allocation error 4.\n");
+			delete[] rxBuff1;
+			delete[] rxBuff2;
+			delete[] rxBuff3;
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer.ReceiveData(rxBuff2, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize2, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize3 = m_consumer.ReceiveData(rxBuff3, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize3, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize4 = m_consumer.ReceiveData(rxBuff4, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize4, m_consumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGoldenNat(
+			m_sendBuffer, m_sendSize,
+			rxBuff1, receivedSize,
+			m_private_ip, m_public_ip,
+			m_private_port, m_public_port,
+			true))
+		{
+			LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		char recievedBuffer[256] = { 0 };
+		char SentBuffer[256] = { 0 };
+		char recievedBuffer2[256] = { 0 };
+		char SentBuffer2[256] = { 0 };
+		char recievedBuffer3[256] = { 0 };
+		char SentBuffer3[256] = { 0 };
+		char recievedBuffer4[256] = { 0 };
+		char SentBuffer4[256] = { 0 };
+		size_t j;
+
+		for (j = 0; j < m_sendSize; j++)
+			snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+		for (j = 0; j < receivedSize; j++)
+			snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+		LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+
+		delete[] rxBuff1;
+
+		isSuccess &= CompareResultVsGoldenNat(
+			m_sendBuffer2, m_sendSize2,
+			rxBuff2, receivedSize2,
+			m_private_ip2, m_public_ip2,
+			m_private_port2, m_public_port2,
+			true);
+
+		for (j = 0; j < m_sendSize2; j++)
+			snprintf(&SentBuffer2[3 * j], sizeof(SentBuffer2) - (3 * j + 1), " %02X", m_sendBuffer2[j]);
+		for (j = 0; j < receivedSize2; j++)
+			snprintf(&recievedBuffer2[3 * j], sizeof(recievedBuffer2) - (3 * j + 1), " %02X", rxBuff2[j]);
+		LOG_MSG_STACK("sent Value2 (%zu)\n%s\n, Received Value2(%zu)\n%s\n", m_sendSize2, SentBuffer2, receivedSize2, recievedBuffer2);
+
+		delete[] rxBuff2;
+
+		isSuccess &= CompareResultVsGoldenNat(
+			m_sendBuffer3, m_sendSize3,
+			rxBuff3, receivedSize3,
+			m_private_ip3, m_public_ip3,
+			m_private_port3, m_public_port3,
+			true);
+
+		for (j = 0; j < m_sendSize3; j++)
+			snprintf(&SentBuffer3[3 * j], sizeof(SentBuffer3) - (3 * j + 1), " %02X", m_sendBuffer3[j]);
+		for (j = 0; j < receivedSize3; j++)
+			snprintf(&recievedBuffer3[3 * j], sizeof(recievedBuffer3) - (3 * j + 1), " %02X", rxBuff3[j]);
+		LOG_MSG_STACK("sent Value3 (%zu)\n%s\n, Received Value3(%zu)\n%s\n", m_sendSize3, SentBuffer3, receivedSize3, recievedBuffer3);
+
+		delete[] rxBuff3;
+
+		isSuccess &= CompareResultVsGoldenNat(
+			m_sendBuffer4, m_sendSize4,
+			rxBuff4, receivedSize4,
+			m_private_ip4, m_public_ip4,
+			m_private_port4, m_public_port4,
+			true);
+
+		for (j = 0; j < m_sendSize4; j++)
+			snprintf(&SentBuffer4[3 * j], sizeof(SentBuffer4) - (3 * j + 1), " %02X", m_sendBuffer4[j]);
+		for (j = 0; j < receivedSize4; j++)
+			snprintf(&recievedBuffer4[3 * j], sizeof(recievedBuffer4) - (3 * j + 1), " %02X", rxBuff4[j]);
+		LOG_MSG_STACK("sent Value4 (%zu)\n%s\n, Received Value4(%zu)\n%s\n", m_sendSize4, SentBuffer4, receivedSize4, recievedBuffer4);
+
+		delete[] rxBuff4;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test012: Single PDN dst NAT test expansion table usage                    */
+/* NOTE: other classes are derived from this class - change carefully        */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest012 : public IpaNatBlockTestFixture
+{
+	uint32_t m_target_ip2;
+	uint16_t m_target_port2;
+public:
+	IpaNatBlockTest012()
+	{
+		m_name = "IpaNatBlockTest012";
+		m_description =
+			"NAT block test 012 - single PDN dst NAT test - expansion table usage\
+		1. Generate and commit three routing tables (only one is used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit one filtering rule: (DST & Mask Match). \
+			action go to dst NAT \
+			All DST_IP == (192.23.22.1 & 0.255.255.255)traffic goes to NAT block (public IP filtering) \
+		3. generate and commit two NAT rules so second one is located in expansion table:\
+		   since we use a single public ip this test should work also on pre IPAv4 targets\
+			public ip 192.23.22.1 --> private ip 194.23.22.1  ";
+		m_private_ip = 0xC2171601; /* 194.23.22.1 */
+		m_private_port = 5678;
+		m_private_ip2 = 0xC5171601; /* 197.23.22.1 */
+		m_private_port2 = 5679;
+		m_public_ip = 0xC0171601;   /* "192.23.22.1" */
+		m_public_port = 9050;
+		m_target_ip = 0xC1171601; /* 193.23.22.1 */
+		m_target_port = 1234;
+		m_target_ip2 = 0x1601C117; /* swap m_target_ip to get same hash*/
+		m_target_port2 = m_target_port;
+		Register(*this);
+	}
+
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering\n");
+
+		const char bypass0[20] = "Bypass0";
+		const char bypass1[20] = "Bypass1";
+		const char bypass2[20] = "Bypass2";
+		struct ipa_ioc_get_rt_tbl routing_table0;
+
+		if (!CreateThreeIPv4BypassRoutingTables(bypass0, bypass1, bypass2))
+		{
+			LOG_MSG_ERROR("CreateThreeBypassRoutingTables Failed\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("CreateThreeBypassRoutingTables completed successfully\n");
+		routing_table0.ip = IPA_IP_v4;
+		strlcpy(routing_table0.name, bypass0, sizeof(routing_table0.name));
+		if (!m_routing.GetRoutingTable(&routing_table0))
+		{
+			LOG_MSG_ERROR("m_routing.GetRoutingTable(&routing_table0=0x%p) Failed.\n", &routing_table0);
+			return false;
+		}
+		LOG_MSG_DEBUG("%s route table handle = %u\n", bypass0, routing_table0.hdl);
+
+		IPAFilteringTable FilterTable0;
+		struct ipa_flt_rule_add flt_rule_entry;
+		FilterTable0.Init(IPA_IP_v4, IPA_CLIENT_TEST_PROD, false, 3);
+		LOG_MSG_DEBUG("FilterTable*.Init Completed Successfully..\n");
+
+		// Configuring Filtering Rule No.0
+		FilterTable0.GeneratePresetRule(1, flt_rule_entry);
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1; // return Value
+		flt_rule_entry.status = -1; // return value
+		flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+		flt_rule_entry.rule.rt_tbl_hdl = routing_table0.hdl;
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00FFFFFF; // Mask
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = m_public_ip; // Filter DST_IP == 192.23.22.1
+		flt_rule_entry.rule.pdn_idx = 0;
+		flt_rule_entry.rule.set_metadata = 0;
+		if (
+			((uint8_t)-1 == FilterTable0.AddRuleToTable(flt_rule_entry)) ||
+			!m_filtering.AddFilteringRule(FilterTable0.GetFilteringTable())
+			)
+		{
+			LOG_MSG_ERROR("Error Adding Rule to Filter Table, aborting...\n");
+			return false;
+		}
+		else
+		{
+			LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", FilterTable0.ReadRuleFromTable(0)->flt_rule_hdl, FilterTable0.ReadRuleFromTable(0)->status);
+		}
+
+		//NAT table and rules creation
+		int total_entries = 20;
+		int ret;
+		ipa_nat_ipv4_rule ipv4_rule;
+		uint32_t pub_ip_add = m_public_ip;
+
+		ret = ipa_nat_add_ipv4_tbl(pub_ip_add, m_mem_type, total_entries, &m_tbl_hdl);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed creating NAT table\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("nat table added, hdl %d, public ip 0x%X\n", m_tbl_hdl,
+			pub_ip_add);
+
+		ipv4_rule.target_ip = m_target_ip;
+		ipv4_rule.target_port = m_target_port;
+		ipv4_rule.private_ip = m_private_ip;
+		ipv4_rule.private_port = m_private_port;
+		ipv4_rule.protocol = IPPROTO_TCP;
+		ipv4_rule.public_port = m_public_port;
+		ipv4_rule.pdn_index = 0;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 0\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("NAT rule added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d, $d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port, ipv4_rule.pdn_index);
+
+		ipv4_rule.target_ip = m_target_ip2;
+		ipv4_rule.target_port = m_target_port2;
+
+		// private IPs are not part of the dst NAT entry hash calculation
+		ipv4_rule.private_ip = m_private_ip2;
+		ipv4_rule.private_port = m_private_port2;
+
+		ret = ipa_nat_add_ipv4_rule(m_tbl_hdl, &ipv4_rule, &m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed adding NAT rule 0\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("NAT rule 2 added, hdl %d, data: 0x%X, %d, 0x%X, %d, %d, %d, $d\n",
+			m_nat_rule_hdl1, ipv4_rule.target_ip, ipv4_rule.target_port,
+			ipv4_rule.private_ip, ipv4_rule.private_port,
+			ipv4_rule.protocol, ipv4_rule.public_port, ipv4_rule.pdn_index);
+
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}// AddRules()
+
+	virtual bool ModifyPackets()
+	{
+		uint32_t address;
+		uint16_t port;
+		char flags = 0x18;
+
+		address = htonl(m_public_ip);
+		memcpy(&m_sendBuffer[IPV4_DST_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_public_port);
+		memcpy(&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+
+		address = htonl(m_target_ip2);
+		memcpy(&m_sendBuffer[IPV4_SRC_ADDR_OFFSET], &address, sizeof(address));
+		port = htons(m_target_port2);
+		memcpy(&m_sendBuffer[IPV4_SRC_PORT_OFFSET], &port, sizeof(port));
+
+		//make sure the FIN flag is not set, otherwise we will get a NAT miss
+		memcpy(&m_sendBuffer[IPV4_TCP_FLAGS_OFFSET], &flags, sizeof(flags));
+
+		return true;
+	}// ModifyPacktes ()
+
+	virtual bool SendPackets()
+	{
+		bool isSuccess = false;
+
+		// Send first packet
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			LOG_MSG_ERROR("SendData failure.\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("sent successfully one packet\n");
+		return true;
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+
+		if (NULL == rxBuff1)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGoldenNat(
+			m_sendBuffer, m_sendSize,
+			rxBuff1, receivedSize,
+			m_private_ip2, m_public_ip,
+			m_private_port2, m_public_port,
+			false))
+		{
+			LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		char recievedBuffer[256] = { 0 };
+		char SentBuffer[256] = { 0 };
+		size_t j;
+
+		for (j = 0; j < m_sendSize; j++)
+			snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+		for (j = 0; j < receivedSize; j++)
+			snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+		LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+
+		delete[] rxBuff1;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test013: Single PDN dst NAT expansion rule deletion test                 */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest013 : public IpaNatBlockTest012
+{
+public:
+	IpaNatBlockTest013()
+	{
+		m_name = "IpaNatBlockTest013";
+		m_description =
+			"NAT block test 013 - single PDN dst NAT test - expansion table rule deletion\
+		1. Generate and commit three routing tables (only one is used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit one filtering rule: (DST & Mask Match). \
+			action go to dst NAT \
+			All DST_IP == (192.23.22.1 & 0.255.255.255)traffic goes to NAT block (public IP filtering) \
+		3. generate and commit two NAT rules so second one is located in expansion table:\
+		   since we use a single public ip this test should work also on pre IPAv4 targets\
+			public ip 192.23.22.1 --> private ip 194.23.22.1\
+		4. delete NAT rule and expect NAT miss";
+	}
+
+
+	virtual bool AddRules()
+	{
+		LOG_MSG_DEBUG("Entering\n");
+
+		int ret = IpaNatBlockTest012::AddRules();
+		if (!ret) {
+			LOG_MSG_ERROR("Leaving, failed Adding test 012 rules 0\n");
+			return false;
+		}
+
+		ret = ipa_nat_del_ipv4_rule(m_tbl_hdl, m_nat_rule_hdl1);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed deleting NAT rule 1\n");
+			return false;
+		}
+		LOG_MSG_DEBUG("NAT rule deleted\n");
+
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}// AddRules()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+
+		if (NULL == rxBuff1)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		if (receivedSize) {
+			LOG_MSG_ERROR("Data received - test failed!\n");
+			isSuccess = false;
+
+			// Compare results for debug in the case of failure only
+			if (!CompareResultVsGoldenNat(
+				m_sendBuffer, m_sendSize,
+				rxBuff1, receivedSize,
+				m_private_ip2, m_public_ip,
+				m_private_port2, m_public_port,
+				false))
+			{
+				LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			}
+			else {
+				LOG_MSG_ERROR("Comparison of Buffer0 succeeded - NAT rule was hit despite deletion!\n");
+			}
+
+			char recievedBuffer[256] = { 0 };
+			char SentBuffer[256] = { 0 };
+			size_t j;
+
+			for (j = 0; j < m_sendSize; j++)
+				snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+			for (j = 0; j < receivedSize; j++)
+				snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+			LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+		}
+
+		delete[] rxBuff1;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test014: Single PDN src NAT zero PDN test                                 */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest014 : public IpaNatBlockTest001
+{
+public:
+	IpaNatBlockTest014()
+	{
+		m_name = "IpaNatBlockTest014";
+		m_description =
+			"NAT block test 014 - single PDN src NAT PDN zeroing test\
+		1. Generate and commit three routing tables (only one is used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit one filtering rule: (DST & Mask Match). \
+			action go to src NAT \
+			All DST_IP == (193.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+		3. generate and commit one NAT rule:\
+			private ip 194.23.22.1 --> public ip 192.23.22.1\
+		4. modify PDN entry 0 and expect NAT miss";
+		m_minIPAHwType = IPA_HW_v4_0;
+	}
+
+
+	virtual bool AddRules()
+	{
+		ipa_nat_pdn_entry pdn_info;
+
+		LOG_MSG_DEBUG("Entering\n");
+
+		int ret = IpaNatBlockTest001::AddRules();
+		if (!ret) {
+			LOG_MSG_ERROR("Leaving, failed Adding test 001 rules 0\n");
+			return false;
+		}
+
+		// modify PDN entry 0 so the NAT rule will get a NAT miss
+		pdn_info.public_ip = 0;
+		pdn_info.src_metadata = 0;
+		pdn_info.dst_metadata = 0;
+		ret = ipa_nat_modify_pdn(m_tbl_hdl, 0, &pdn_info);
+		if (ret) {
+			LOG_MSG_ERROR("Leaving, failed Modifying PDN entry 0 \n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("PDN modified\n");
+
+		LOG_MSG_DEBUG("Leaving\n");
+		return true;
+	}// AddRules()
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+
+		if (NULL == rxBuff1)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		if (receivedSize) {
+			LOG_MSG_ERROR("Data received - test failed!\n");
+			isSuccess = false;
+
+			// Compare results
+			if (!CompareResultVsGoldenNat(
+				m_sendBuffer, m_sendSize,
+				rxBuff1, receivedSize,
+				m_private_ip, m_public_ip,
+				m_private_port, m_public_port,
+				true))
+			{
+				LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			}
+			else {
+				LOG_MSG_ERROR("Comparison of Buffer0 succeeded - NAT rule was hit despite deletion!\n");
+			}
+
+			char recievedBuffer[256] = { 0 };
+			char SentBuffer[256] = { 0 };
+			size_t j;
+
+			for (j = 0; j < m_sendSize; j++)
+				snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+			for (j = 0; j < receivedSize; j++)
+				snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+			LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+		}
+
+		delete[] rxBuff1;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test015: Single PDN src NAT send two packets that will hit the same rule  */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest015 : public IpaNatBlockTest001
+{
+public:
+	IpaNatBlockTest015()
+	{
+		m_name = "IpaNatBlockTest015";
+		m_description =
+			"NAT block test 015 - single PDN src NAT hit the same rule twice\
+		1. Generate and commit three routing tables (only one is used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit one filtering rule: (DST & Mask Match). \
+			action go to src NAT \
+			All DST_IP == (193.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+		3. generate and commit one NAT rule:\
+			private ip 194.23.22.1 --> public ip 192.23.22.1\
+		4. send two pakcets and verify NATing";
+	}
+
+	virtual bool SendPackets()
+	{
+		bool ret = IpaNatBlockTest001::SendPackets();
+		if (!ret)
+		{
+			LOG_MSG_ERROR("failed sending first pakcket.\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("first packet sent succesfully.\n");
+
+		ret = IpaNatBlockTest001::SendPackets();
+		if (!ret)
+		{
+			LOG_MSG_ERROR("failed sending second pakcket.\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("second packet sent succesfully.\n");
+
+		return true;
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		bool isSuccess = true;
+
+		isSuccess &= IpaNatBlockTest001::ReceivePacketsAndCompare();
+		if (!isSuccess)
+		{
+			LOG_MSG_ERROR("failed to receive\\compare first packet.\n");
+		}
+
+		isSuccess &= IpaNatBlockTest001::ReceivePacketsAndCompare();
+		if (!isSuccess)
+		{
+			LOG_MSG_ERROR("failed to receive\\compare second packet.\n");
+		}
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test016: Single PDN dst NAT send two packets that will hit the same rule  */
+/*---------------------------------------------------------------------------*/
+class IpaNatBlockTest016 : public IpaNatBlockTest002
+{
+public:
+	IpaNatBlockTest016()
+	{
+		m_name = "IpaNatBlockTest016";
+		m_description =
+			"NAT block test 016 - single PDN dst NAT hit the same rule twice\
+		1. Generate and commit three routing tables (only one is used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit one filtering rule: (DST & Mask Match). \
+			action go to dst NAT \
+			All DST_IP == (192.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+		3. generate and commit one NAT rule:\
+			public ip 192.23.22.1 --> private ip 194.23.22.1\
+		4. send two pakcets and verify NATing";
+	}
+
+	virtual bool SendPackets()
+	{
+		bool ret = IpaNatBlockTest002::SendPackets();
+		if (!ret)
+		{
+			LOG_MSG_ERROR("failed sending first pakcket.\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("first packet sent succesfully.\n");
+
+		ret = IpaNatBlockTest002::SendPackets();
+		if (!ret)
+		{
+			LOG_MSG_ERROR("failed sending second pakcket.\n");
+			return false;
+		}
+
+		LOG_MSG_DEBUG("second packet sent succesfully.\n");
+
+		return true;
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		bool isSuccess = true;
+
+		isSuccess &= IpaNatBlockTest002::ReceivePacketsAndCompare();
+		if (!isSuccess)
+		{
+			LOG_MSG_ERROR("failed to receive\\compare first packet.\n");
+		}
+
+		isSuccess &= IpaNatBlockTest002::ReceivePacketsAndCompare();
+		if (!isSuccess)
+		{
+			LOG_MSG_ERROR("failed to receive\\compare second packet.\n");
+		}
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------------*/
+/* Test017: Multi PDN src NAT test with identical private IPs and different ports  */
+/*---------------------------------------------------------------------------------*/
+class IpaNatBlockTest017 : public IpaNatBlockTest003
+{
+public:
+	IpaNatBlockTest017()
+	{
+		m_name = "IpaNatBlockTest017";
+		m_description =
+		"NAT block test 017 - Multi PDN src NAT test with identical private IPs\
+		1. Generate and commit three routing tables (two are used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit two filtering rule: (DST & Mask Match). \
+			- action go to src NAT \
+			  All SRC_IP == (194.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+			  All SRC_IP == (197.23.22.1 & 0.255.255.255)traffic goes to NAT block - not relevant for this test \
+		3. generate and commit two NAT rules:\
+			private ip 194.23.22.1 && port 5678--> public ip 192.23.22.1 \
+			private ip 194.23.22.1 && port 5679--> public ip 195.23.22.1";
+		m_private_ip2 = m_private_ip;
+	}
+
+	virtual bool ReceivePacketsAndCompare()
+	{
+		// we cannot just use test 003 ReceivePacketsAndCompare since the filtering rules send the
+		// packets to two different pipes, but since the private IPs are now equal the second filtering rule
+		// won't be hit so we need to recive the second packet on the first pipe
+
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+
+		if (rxBuff1 == NULL)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			if (rxBuff2)
+				delete[] rxBuff2;
+			return false;
+		}
+
+		if (rxBuff2 == NULL)
+		{
+			LOG_MSG_ERROR("Memory allocation error.\n");
+			delete[] rxBuff1;
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer.ReceiveData(rxBuff2, 0x400);
+		LOG_MSG_DEBUG("Received %zu bytes on %s.\n", receivedSize2, m_consumer.m_fromChannelName.c_str());
+
+		// Compare results
+		if (!CompareResultVsGoldenNat(
+			m_sendBuffer, m_sendSize,
+			rxBuff1, receivedSize,
+			m_private_ip, m_public_ip,
+			m_private_port, m_public_port,
+			true))
+		{
+			LOG_MSG_ERROR("Comparison of Buffer0 Failed!\n");
+			isSuccess = false;
+		}
+
+		char recievedBuffer[256] = { 0 };
+		char SentBuffer[256] = { 0 };
+		char recievedBuffer2[256] = { 0 };
+		char SentBuffer2[256] = { 0 };
+		size_t j;
+
+		for (j = 0; j < m_sendSize; j++)
+			snprintf(&SentBuffer[3 * j], sizeof(SentBuffer) - (3 * j + 1), " %02X", m_sendBuffer[j]);
+		for (j = 0; j < receivedSize; j++)
+			snprintf(&recievedBuffer[3 * j], sizeof(recievedBuffer) - (3 * j + 1), " %02X", rxBuff1[j]);
+		LOG_MSG_STACK("sent Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n", m_sendSize, SentBuffer, receivedSize, recievedBuffer);
+
+		delete[] rxBuff1;
+
+		isSuccess &= CompareResultVsGoldenNat(
+			m_sendBuffer2, m_sendSize2,
+			rxBuff2, receivedSize2,
+			m_private_ip2, m_public_ip2,
+			m_private_port2, m_public_port2,
+			true);
+
+		for (j = 0; j < m_sendSize2; j++)
+			snprintf(&SentBuffer2[3 * j], sizeof(SentBuffer2) - (3 * j + 1), " %02X", m_sendBuffer2[j]);
+		for (j = 0; j < receivedSize2; j++)
+			snprintf(&recievedBuffer2[3 * j], sizeof(recievedBuffer2) - (3 * j + 1), " %02X", rxBuff2[j]);
+		LOG_MSG_STACK("sent Value2 (%zu)\n%s\n, Received Value2(%zu)\n%s\n", m_sendSize2, SentBuffer2, receivedSize2, recievedBuffer2);
+
+		delete[] rxBuff2;
+
+		return isSuccess;
+	}
+};
+
+/*---------------------------------------------------------------------------------*/
+/* Test018: Multi PDN dst NAT test with identical private IPs and different ports  */
+/*---------------------------------------------------------------------------------*/
+class IpaNatBlockTest018 : public IpaNatBlockTest004
+{
+public:
+	IpaNatBlockTest018()
+	{
+		m_name = "IpaNatBlockTest018";
+		m_description =
+		"NAT block test 018 - Multi PDN dst NAT test with identical private IPs\
+		1. Generate and commit three routing tables (two are used). \
+			Each table contains a single \"bypass\" rule (all data goes to output pipe 0, 1  and 2 (accordingly)) \
+		2. Generate and commit two filtering rule: (DST & Mask Match). \
+			- action go to dst NAT \
+			  All DST_IP == (192.23.22.1 & 0.255.255.255)traffic goes to NAT block \
+			  All DST_IP == (195.23.22.1 & 0.255.255.255)traffic goes to NAT block - not releveant for this test\
+		3. generate and commit two NAT rules:\
+			private ip 194.23.22.1 --> public ip 192.23.22.1 && port 9050\
+			private ip 194.23.22.1 --> public ip 192.23.22.1 && port 9051";
+		m_private_ip2 = m_private_ip;
+	}
+};
+
+static class IpaNatBlockTest001 IpaNatBlockTest001;//single PDN src NAT test
+static class IpaNatBlockTest002 IpaNatBlockTest002;//single PDN dst NAT test
+static class IpaNatBlockTest003 IpaNatBlockTest003;//multi PDN (tuple) src NAT test
+static class IpaNatBlockTest004 IpaNatBlockTest004;//multi PDN (tuple) dst NAT test
+static class IpaNatBlockTest005 IpaNatBlockTest005;//single PDN src NAT test - src metadata replacement
+static class IpaNatBlockTest006 IpaNatBlockTest006;//single PDN dst NAT test - dst metadata replacement
+static class IpaNatBlockTest007 IpaNatBlockTest007;//hashable routing rule with dst NAT test
+static class IpaNatBlockTest008 IpaNatBlockTest008;//Multi PDN src NAT test match PDN by input from filtering block
+static class IpaNatBlockTest009 IpaNatBlockTest009;//single PDN src NAT rule deletion test
+static class IpaNatBlockTest010 IpaNatBlockTest010;//single PDN dst NAT rule deletion test
+static class IpaNatBlockTest011 IpaNatBlockTest011;//Multi PDN src NAT - MAX number of PDNs test
+static class IpaNatBlockTest012 IpaNatBlockTest012;//Single PDN dst NAT test expansion table usage
+static class IpaNatBlockTest013 IpaNatBlockTest013;//Single PDN dst NAT test expansion table delete test
+static class IpaNatBlockTest014 IpaNatBlockTest014;//single PDN src NAT zero PDN test
+static class IpaNatBlockTest015 IpaNatBlockTest015;//single PDN src NAT test - send two packets that will hit the same rule
+static class IpaNatBlockTest016 IpaNatBlockTest016;//single PDN dst NAT test - send two packets that will hit the same rule
+static class IpaNatBlockTest017 IpaNatBlockTest017;//multi PDN (tuple) src NAT test - identical private IPs different ports
+static class IpaNatBlockTest018 IpaNatBlockTest018;//multi PDN (tuple) dst NAT test - identical private IPs different ports
+

+ 729 - 0
kernel-tests/Pipe.cpp

@@ -0,0 +1,729 @@
+/*
+ * Copyright (c) 2017-2018,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "Pipe.h"
+#include "TestsUtils.h"
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+//Do not change those default values due to the fact that some test may relay on those default values.
+//In case you need a change of the field do this in a derived class.
+
+//Dest MAC(6 bytes) Src MAC(6 Bytes) EtherType(2 Bytes)
+unsigned char Pipe::m_pUsbHeader[] = { 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xB1, 0xB2,
+		0xB3, 0xB4, 0xB5, 0xB6, 0xC1, 0xC2 };
+unsigned char Pipe::m_pA2NDUNHeader[] =
+		{ 0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xC1, 0xC2 };
+//unsigned char Pipe::m_pA2DUNHeader[]  = {};
+//unsigned char Pipe::m_pQ6LANHeader[]  = {};
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+Pipe::Pipe(enum ipa_client_type nClientType,
+		IPATestConfiguration eConfiguration) :
+		m_Fd(-1), m_nHeaderLengthRemove(0),
+		m_nHeaderLengthAdd(0), m_pHeader(NULL), m_pInodePath(NULL),
+		m_bInitialized(false), m_ExceptionPipe(false) {
+	m_nClientType = nClientType;
+	m_eConfiguration = eConfiguration;
+}
+
+Pipe::Pipe(IPATestConfiguration eConfiguration) :
+	m_Fd(-1), m_nHeaderLengthRemove(0),
+	m_nHeaderLengthAdd(0), m_pHeader(NULL), m_pInodePath(NULL),
+	m_bInitialized(false), m_ExceptionPipe(true) {
+	m_eConfiguration = eConfiguration;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+Pipe::~Pipe() {
+	//Nothing to be done at this point...
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool Pipe::Init() {
+	int tries_cnt = 1;
+	SetSpecificClientParameters(m_nClientType, m_eConfiguration);
+	//By examining the Client type we will map the inode device name
+	while (tries_cnt <= 10000) {
+		m_Fd = open(m_pInodePath, O_RDWR);
+		if (-1 != m_Fd)
+			break;
+
+		// Sleep for 5 msec
+		usleep(5000);
+		++tries_cnt;
+	}
+	LOG_MSG_DEBUG("open retries_cnt=%d\n", tries_cnt);
+	if (-1 == m_Fd) {
+		LOG_MSG_ERROR("Failed to open %s", m_pInodePath);
+		return false;
+	}
+	m_bInitialized = true;
+	return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void Pipe::Destroy() {
+	if (false == m_bInitialized) {
+		LOG_MSG_ERROR("Pipe is being used without being initialized!");
+		return;
+	}
+	close(m_Fd);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+int Pipe::Send(unsigned char * pBuffer, size_t nBytesToSend) {
+	if (false == m_bInitialized) {
+		LOG_MSG_ERROR("Pipe is being used without being initialized!");
+		return 0;
+	}
+	size_t nBytesWritten = 0;
+	nBytesWritten = write(m_Fd, pBuffer, nBytesToSend);
+	return nBytesWritten;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+int Pipe::AddHeaderAndSend(unsigned char * pIpPacket, size_t nIpPacketSize) {
+	int retval;
+
+	if (false == m_bInitialized) {
+		LOG_MSG_ERROR("Pipe is being used without being initialized!");
+		return 0;
+	}
+	size_t nBytesToWrite = nIpPacketSize + m_nHeaderLengthAdd;
+	//Allocate new buffer for the Header and IP packet:
+	unsigned char *pLinkLayerAndIpPacket = new unsigned char[nBytesToWrite];
+	if (!pLinkLayerAndIpPacket) {
+		LOG_MSG_ERROR("Memory allocation failure.");
+		return 0;
+	}
+
+	//put the header first:
+	memcpy(pLinkLayerAndIpPacket, m_pHeader, m_nHeaderLengthAdd);
+	//Then add the IP packet:
+	memcpy(pLinkLayerAndIpPacket + m_nHeaderLengthAdd, pIpPacket,
+			nIpPacketSize);
+	//Call the Send method which will send the new created buffer(which contains the IP packet with the Header):
+	retval = Send(pLinkLayerAndIpPacket, nBytesToWrite);
+	delete[] pLinkLayerAndIpPacket;
+
+	return retval;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+int Pipe::Receive(unsigned char *pBuffer, size_t nBytesToReceive) {
+	if (false == m_bInitialized) {
+		LOG_MSG_ERROR("Pipe is being used without being initialized!");
+		return 0;
+	}
+	size_t nBytesRead = 0;
+	nBytesRead = read(m_Fd, (void*) pBuffer, nBytesToReceive);
+	return nBytesRead;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+int Pipe::ReceiveAndRemoveHeader(unsigned char *pIpPacket, size_t nIpPacketSize) {
+	if (false == m_bInitialized) {
+		LOG_MSG_ERROR("Pipe is being used without being initialized!");
+		return 0;
+	}
+	size_t nBytesToRead = nIpPacketSize + m_nHeaderLengthRemove;
+	unsigned char *pPacket = new unsigned char[nBytesToRead];
+	if (!pPacket) {
+		LOG_MSG_ERROR("Memory allocation failure.");
+		return 0;
+	}
+	size_t nReceivedBytes = Receive(pPacket, nBytesToRead);
+	if (nReceivedBytes != nBytesToRead) {
+		LOG_MSG_ERROR("Pipe was asked to receive an IP packet "
+			      "of size %d, however only %d bytes were read "
+			      "while the header size is %d",
+			      nIpPacketSize,
+			      nReceivedBytes,
+			      m_nHeaderLengthRemove);
+		delete[] pPacket;
+		return nReceivedBytes - m_nHeaderLengthRemove;
+	}
+
+	memcpy(pIpPacket, pPacket + m_nHeaderLengthRemove, nIpPacketSize);
+	delete[] pPacket;
+
+	return (nReceivedBytes - m_nHeaderLengthRemove);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+enum ipa_client_type Pipe::GetClientType() {
+	if (false == m_bInitialized) {
+		LOG_MSG_ERROR("Pipe is being used without being initialized!");
+		return IPA_CLIENT_HSIC1_PROD;
+	}
+	return m_nClientType;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void Pipe::SetSpecificClientParameters(
+		enum ipa_client_type nClientType,
+		IPATestConfiguration eConfiguration) {
+	switch (eConfiguration) {
+	case IPA_TEST_CONFIFURATION_0:
+		break;
+	case IPA_TEST_CONFIFURATION_1:
+		switch (nClientType) {
+		case (IPA_CLIENT_TEST_PROD):
+			m_pInodePath = CONFIG_1_FROM_USB1_TO_IPA_DMA;
+			m_nHeaderLengthAdd = sizeof(m_pUsbHeader);
+			m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+			m_pHeader = m_pUsbHeader;
+			LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_PROD ");
+			break;
+		case (IPA_CLIENT_TEST_CONS):
+			m_pInodePath = CONFIG_1_FROM_IPA_TO_USB1_DMA;
+			m_nHeaderLengthAdd = sizeof(m_pUsbHeader);
+			m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+			m_pHeader = m_pUsbHeader;
+			LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_CONS");
+			break;
+		default:
+			LOG_MSG_ERROR("IPA_TEST_CONFIFURATION_1 switch in default "
+			"nClientType = %d is not supported ", nClientType);
+			break;
+		}
+		break;
+	case IPA_TEST_CONFIFURATION_2:
+		switch (nClientType) {
+		case (IPA_CLIENT_TEST_PROD):
+			m_pInodePath = CONFIG_2_FROM_USB_TO_IPA;
+			m_nHeaderLengthAdd = sizeof(m_pUsbHeader);
+			m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+			m_pHeader = m_pUsbHeader;
+			LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_PROD");
+			break;
+		case (IPA_CLIENT_TEST2_CONS):
+			m_pInodePath = CONFIG_2_FROM_IPA_TO_A2_NDUN;
+			m_nHeaderLengthAdd = sizeof(m_pA2NDUNHeader);
+			m_nHeaderLengthRemove = sizeof(m_pA2NDUNHeader);
+			m_pHeader = m_pA2NDUNHeader;
+			LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST2_CONS");
+			break;
+		default:
+			LOG_MSG_ERROR("IPA_TEST_CONFIFURATION_2 switch in default "
+			"nClientType = %d is not supported ", nClientType);
+			break;
+		}
+		break;
+	case IPA_TEST_CONFIFURATION_3:
+		switch (nClientType) {
+		case IPA_CLIENT_TEST2_PROD:
+			m_pInodePath = CONFIG_3_FROM_A2_NDUN_TO_IPA;
+			m_nHeaderLengthAdd = sizeof(m_pA2NDUNHeader);
+			m_nHeaderLengthRemove = sizeof(m_pA2NDUNHeader);
+			m_pHeader = m_pA2NDUNHeader;
+			LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST2_PROD");
+			break;
+		case IPA_CLIENT_TEST_CONS:
+			m_pInodePath = CONFIG_3_FROM_IPA_TO_USB1;
+			m_nHeaderLengthAdd = sizeof(m_pUsbHeader);
+			m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+			m_pHeader = m_pUsbHeader;
+			LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_CONS");
+			break;
+		case IPA_CLIENT_TEST2_CONS:
+			m_pInodePath = CONFIG_3_FROM_IPA_TO_A2_NDUN;
+			m_nHeaderLengthAdd = sizeof(m_pA2NDUNHeader);
+			m_nHeaderLengthRemove = sizeof(m_pA2NDUNHeader);
+			m_pHeader = m_pA2NDUNHeader;
+			LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST2_CONS");
+			break;
+		case IPA_CLIENT_TEST4_CONS:
+			//TODO add when applicable
+			m_pInodePath = CONFIG_3_FROM_IPA_TO_Q6_LAN;
+			m_nHeaderLengthAdd = 0;
+			m_nHeaderLengthRemove = 0;
+			m_pHeader = 0;
+			LOG_MSG_INFO("IPA_CLIENT_TEST4_CONS is not supported yet");
+			break;
+		default:
+			LOG_MSG_INFO("IPA_TEST_CONFIFURATION_3 switch in default "
+			"nClientType = %d is not supported ", nClientType);
+			break;
+		}
+		break;
+	case IPA_TEST_CONFIFURATION_7:
+		if (m_ExceptionPipe) {
+			m_pInodePath = CONFIG_7_FROM_IPA_TO_A5_EXCEPTION;
+			m_nHeaderLengthAdd = 0; //No send
+			m_nHeaderLengthRemove = 8; //A5Mux header size without retained source header
+			m_pHeader = NULL; //No header to send
+			LOG_MSG_INFO("Setting parameters for A5_Exception ");
+			break;
+		}
+
+		if (nClientType == IPA_CLIENT_TEST_PROD) {
+			m_pInodePath = CONFIG_7_FROM_USB1_TO_IPA;
+			m_nHeaderLengthAdd = 0;
+			m_nHeaderLengthRemove = 0;
+			m_pHeader = NULL;
+			LOG_MSG_INFO(
+					"Setting parameters for FROM_USB1_TO_IPA - no header addition/removal");
+		} else {
+			LOG_MSG_INFO("IPA_TEST_CONFIFURATION_7 switch in default "
+			"nClientType = %d is not supported ", nClientType);
+		}
+		break;
+	case IPA_TEST_CONFIGURATION_8:
+	    switch(nClientType)
+	    {
+	    case (IPA_CLIENT_TEST_PROD):
+	      m_pInodePath          = CONFIG_8_DEAGG_TO_IPA_NO_AGG;
+	      m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+	      m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+	      m_pHeader             = m_pUsbHeader;
+	      LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_PROD ");
+	      break;
+	    case (IPA_CLIENT_TEST_CONS):
+	      m_pInodePath          = CONFIG_8_FROM_IPA_AGG;
+	      m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+	      m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+	      m_pHeader             = m_pUsbHeader;
+	      LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_CONS");
+	      break;
+	    case (IPA_CLIENT_TEST3_PROD):
+	      m_pInodePath          = CONFIG_8_NO_AGG_TO_IPA_AGG;
+	      m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+	      m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+	      m_pHeader             = m_pUsbHeader;
+	      LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST3_PROD ");
+	      break;
+	    case (IPA_CLIENT_TEST3_CONS):
+	      m_pInodePath          = CONFIG_8_FROM_IPA_NO_AGG;
+	      m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+	      m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+	      m_pHeader             = m_pUsbHeader;
+	      LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST3_CONS");
+	      break;
+	    case (IPA_CLIENT_TEST2_PROD):
+	      m_pInodePath          = CONFIG_8_DEAGG_TO_IPA_AGG;
+	      m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+	      m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+	      m_pHeader             = m_pUsbHeader;
+	      LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST2_PROD");
+	      break;
+	    case (IPA_CLIENT_TEST2_CONS):
+	      m_pInodePath          = CONFIG_8_DEAGG_FROM_IPA_AGG;
+	      m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+	      m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+	      m_pHeader             = m_pUsbHeader;
+	      LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST2_CONS");
+	      break;
+	    case (IPA_CLIENT_TEST4_PROD):
+	      m_pInodePath          = CONFIG_8_NO_AGG_TO_IPA_AGG_TIME;
+	      m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+	      m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+	      m_pHeader             = m_pUsbHeader;
+	      LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST4_PROD");
+	      break;
+	    default:
+	      LOG_MSG_ERROR("IPA_TEST_CONFIFURATION_8 switch in default "
+	                    "nClientType = %d is not supported ",
+	                    nClientType);
+	      break;
+	    }
+	    break;
+	case IPA_TEST_CONFIGURATION_9:
+		switch(nClientType)
+		{
+		case (IPA_CLIENT_TEST_PROD):
+		  m_pInodePath          = CONFIG_9_DEAGG_TO_IPA_NO_AGG;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_PROD ");
+		  break;
+		case (IPA_CLIENT_TEST_CONS):
+		  m_pInodePath          = CONFIG_9_FROM_IPA_AGG;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_CONS");
+		  break;
+		case (IPA_CLIENT_TEST3_PROD):
+		  m_pInodePath          = CONFIG_9_NO_AGG_TO_IPA_AGG;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST3_PROD ");
+		  break;
+		case (IPA_CLIENT_TEST3_CONS):
+		  m_pInodePath          = CONFIG_9_FROM_IPA_NO_AGG;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST3_CONS");
+		  break;
+		case (IPA_CLIENT_TEST2_PROD):
+		  m_pInodePath          = CONFIG_9_DEAGG_TO_IPA_AGG;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST2_PROD");
+		  break;
+		case (IPA_CLIENT_TEST2_CONS):
+		  m_pInodePath          = CONFIG_9_DEAGG_FROM_IPA_AGG;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST2_CONS");
+		  break;
+		case (IPA_CLIENT_TEST4_PROD):
+		  m_pInodePath          = CONFIG_9_NO_AGG_TO_IPA_AGG_TIME;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST4_PROD");
+		  break;
+		default:
+		  LOG_MSG_ERROR("IPA_TEST_CONFIFURATION_9 switch in default "
+				  	  	  "nClientType = %d is not supported ",
+				  	  	  nClientType);
+		  break;
+		}
+		break;
+	case IPA_TEST_CONFIGURATION_10:
+	  	switch(nClientType)
+	  	{
+	  	case (IPA_CLIENT_TEST_PROD):
+	  	  m_pInodePath          = CONFIG_10_TO_IPA_AGG_ZERO_LIMITS;
+	  	  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+	  	  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+	  	  m_pHeader             = m_pUsbHeader;
+	  	  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_PROD");
+	  	  break;
+	  	case (IPA_CLIENT_TEST_CONS):
+		  m_pInodePath          = CONFIG_10_FROM_IPA_AGG_ZERO_LIMITS;
+	  	  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+	  	  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+	  	  m_pHeader             = m_pUsbHeader;
+	  	  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_CONS");
+	  	  break;
+	  	default:
+	  	  LOG_MSG_ERROR("IPA_TEST_CONFIFURATION_10 switch in default "
+	  			  	  	  "nClientType = %d is not supported ",
+	  			  	  	  	  nClientType);
+	  	  break;
+	  	}
+	  	break;
+	case IPA_TEST_CONFIGURATION_11:
+		switch(nClientType)
+		{
+		case (IPA_CLIENT_TEST_PROD):
+		  m_pInodePath          = CONFIG_11_TO_IPA;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_PROD");
+		  break;
+		case (IPA_CLIENT_TEST2_CONS):
+		  m_pInodePath          = CONFIG_11_FROM_IPA_AGG;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST2_CONS");
+		  break;
+		case (IPA_CLIENT_TEST2_PROD):
+		  m_pInodePath          = CONFIG_11_TO_IPA_DEAGG;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST2_PROD");
+		  break;
+		case (IPA_CLIENT_TEST3_CONS):
+		  m_pInodePath          = CONFIG_11_FROM_IPA;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST3_CONS");
+		  break;
+		case (IPA_CLIENT_TEST_CONS):
+		  m_pInodePath          = CONFIG_11_FROM_IPA_AGG_TIME;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_CONS");
+		  break;
+		case (IPA_CLIENT_TEST4_CONS):
+		  m_pInodePath          = CONFIG_11_FROM_IPA_ZERO_LIMITS;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST4_CONS");
+		  break;
+		default:
+		  LOG_MSG_ERROR("IPA_TEST_CONFIFURATION_11 switch in default "
+				  	  	  "nClientType = %d is not supported ",
+				  	  	  	  nClientType);
+		  break;
+		}
+		break;
+	case IPA_TEST_CONFIGURATION_12:
+		switch(nClientType)
+		{
+		case (IPA_CLIENT_TEST_PROD):
+		  m_pInodePath          = CONFIG_12_TO_IPA;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_PROD");
+		  break;
+		case (IPA_CLIENT_TEST2_CONS):
+		  m_pInodePath          = CONFIG_12_FROM_IPA_AGG;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST2_CONS");
+		  break;
+		case (IPA_CLIENT_TEST2_PROD):
+		  m_pInodePath          = CONFIG_12_TO_IPA_DEAGG;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST2_PROD");
+		  break;
+		case (IPA_CLIENT_TEST3_CONS):
+		  m_pInodePath          = CONFIG_12_FROM_IPA;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST3_CONS");
+		  break;
+		case (IPA_CLIENT_TEST_CONS):
+		  m_pInodePath          = CONFIG_12_FROM_IPA_AGG_TIME;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_CONS");
+		  break;
+		case (IPA_CLIENT_TEST4_CONS):
+		  m_pInodePath          = CONFIG_12_FROM_IPA_ZERO_LIMITS;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST4_CONS");
+		  break;
+		default:
+		  LOG_MSG_ERROR("IPA_TEST_CONFIFURATION_12 switch in default "
+				  	  	  "nClientType = %d is not supported ",
+				  	  	  	  nClientType);
+		  break;
+		}
+		break;
+	case IPA_TEST_CONFIGURATION_17:
+		switch(nClientType)
+		{
+		case (IPA_CLIENT_TEST_PROD):
+		  m_pInodePath          = CONFIG_17_TO_IPA;
+		  m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		  m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		  m_pHeader             = m_pUsbHeader;
+		  LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_PROD ");
+		  break;
+	   case (IPA_CLIENT_TEST3_PROD):
+		   m_pInodePath          = CONFIG_17_TO_IPA_NO_HDR;
+		   m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		   m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		   m_pHeader             = m_pUsbHeader;
+		   LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST3_PROD ");
+		   break;
+	   case (IPA_CLIENT_TEST2_CONS):
+		   m_pInodePath          = CONFIG_17_FROM_IPA_AGG;
+		   m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		   m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		   m_pHeader             = m_pUsbHeader;
+		   LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST2_CONS");
+		   break;
+	   case (IPA_CLIENT_TEST2_PROD):
+		   m_pInodePath          = CONFIG_17_TO_IPA_DEAGG;
+		   m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		   m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		   m_pHeader             = m_pUsbHeader;
+		   LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST2_PROD ");
+		   break;
+	   case (IPA_CLIENT_TEST3_CONS):
+		   m_pInodePath          = CONFIG_17_FROM_IPA;
+		   m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		   m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		   m_pHeader             = m_pUsbHeader;
+		   LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST3_CONS");
+		   break;
+	   case (IPA_CLIENT_TEST_CONS):
+		   m_pInodePath          = CONFIG_17_FROM_IPA_AGG_TIME;
+		   m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		   m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		   m_pHeader             = m_pUsbHeader;
+		   LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_CONS");
+		   break;
+	   case (IPA_CLIENT_TEST4_CONS):
+		   m_pInodePath          = CONFIG_17_FROM_IPA_ZERO_LIMITS;
+		   m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+		   m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+		   m_pHeader             = m_pUsbHeader;
+		   LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST4_CONS");
+		   break;
+	   default:
+		   LOG_MSG_ERROR("IPA_TEST_CONFIFURATION_17 switch in default "
+			   "nClientType = %d is not supported ",
+			   nClientType);
+		   break;
+	   }
+	   break;
+	case IPA_TEST_CONFIGURATION_18:
+		switch (nClientType)
+		{
+		case (IPA_CLIENT_TEST_PROD):
+			m_pInodePath          = CONFIG_18_TO_IPA;
+			m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+			m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+			m_pHeader             = m_pUsbHeader;
+			LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_PROD ");
+			break;
+		case (IPA_CLIENT_TEST2_PROD):
+			m_pInodePath          = CONFIG_18_DUMMY_ENDPOINT;
+			m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+			m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+			m_pHeader             = m_pUsbHeader;
+			LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST2_PROD ");
+			break;
+		case (IPA_CLIENT_TEST_CONS):
+			m_pInodePath          = CONFIG_18_FROM_IPA;
+			m_nHeaderLengthAdd    = sizeof(m_pUsbHeader);
+			m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+			m_pHeader             = m_pUsbHeader;
+			LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_CONS");
+			break;
+		default:
+			LOG_MSG_ERROR(
+				"IPA_TEST_CONFIFURATION_18 switch in default "
+				"nClientType = %d is not supported ",
+				nClientType);
+			break;
+		}
+		break;
+	case IPA_TEST_CONFIGURATION_19:
+		switch (nClientType)
+		{
+		case (IPA_CLIENT_TEST_PROD):
+			m_pInodePath = CONFIG_19_FROM_USB_TO_IPA_DMA;
+			m_nHeaderLengthAdd = sizeof(m_pUsbHeader);
+			m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+			m_pHeader = m_pUsbHeader;
+			LOG_MSG_INFO("Setting parameters for IPA_CLIENT_TEST_PROD ");
+			break;
+		case (IPA_CLIENT_TEST_CONS):
+			m_pInodePath = CONFIG_19_FROM_IPA_TO_USB_DMA;
+			m_nHeaderLengthAdd = sizeof(m_pUsbHeader);
+			m_nHeaderLengthRemove = sizeof(m_pUsbHeader);
+			m_pHeader = m_pUsbHeader;
+			LOG_MSG_INFO("Setting parameters for TEST_CONS");
+			break;
+		default:
+			LOG_MSG_ERROR("IPA_TEST_CONFIFURATION_19 switch in default "
+			"nClientType = %d is not supported ", nClientType);
+			break;
+		}
+		break;
+	default:
+	LOG_MSG_ERROR("Pipe::SetSpecificClientParameters "
+	"switch in default eConfiguration = %d ", eConfiguration);
+	break;
+	}
+}/* Pipe::SetSpecificClientParameters() */
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+int Pipe::GetHeaderLengthAdd() {
+	if (false == m_bInitialized) {
+		LOG_MSG_ERROR("Pipe is being used without being initialized!");
+		return 0;
+	}
+	return m_nHeaderLengthAdd;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+int Pipe::GetHeaderLengthRemove() {
+	if (false == m_bInitialized) {
+		LOG_MSG_ERROR("Pipe is being used without being initialized!");
+		return 0;
+	}
+	return m_nHeaderLengthRemove;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool Pipe::ConfigureHolb(unsigned short enable, unsigned timerValue) {
+	if (false == m_bInitialized) {
+		LOG_MSG_ERROR("Pipe is being used without being initialized!");
+		return false;
+	}
+
+	if (IPA_CLIENT_IS_PROD(m_nClientType)) {
+		LOG_MSG_ERROR("Can't configure HOLB on a producer pipe!");
+		return false;
+	}
+
+	struct ipa_test_holb_config test_holb_config;
+
+	test_holb_config.client = m_nClientType;
+	test_holb_config.tmr_val = timerValue;
+	test_holb_config.en = enable;
+
+	LOG_MSG_DEBUG("Sending: client=%d tmr_val=%d en=%d",
+				  test_holb_config.client,
+				  test_holb_config.tmr_val,
+				  test_holb_config.en);
+
+	return configure_holb(&test_holb_config);
+}
+
+bool Pipe::EnableHolb(unsigned timerValue) {
+	return ConfigureHolb(1, timerValue);
+}
+
+bool Pipe::DisableHolb() {
+	return ConfigureHolb(0, 0);
+}
+

+ 151 - 0
kernel-tests/Pipe.h

@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PIPE_H_
+#define _PIPE_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <stdint.h>
+#include "linux/msm_ipa.h"
+#include "Constants.h"
+#include "Logger.h"
+
+using namespace std;
+
+/*This class will be used to interact with the system pipes
+ *by only referring to Client type.
+ *It will allow "raw" data transfer to/from the IPA and
+ *will allow a encapsulation of the header addition/
+ *removal of a packets thus allowing
+ *the test to deal only with IP packet.
+ */
+class Pipe
+{
+
+public:
+	/* see Constants.h for nClientType / eConfiguration */
+	Pipe(enum ipa_client_type nClientType,
+		  IPATestConfiguration eConfiguration);
+	/* exception pipe Ctor */
+	Pipe(IPATestConfiguration eConfiguration);
+	~Pipe();
+
+	/*In this method the actual inode openning will occur.*/
+	bool Init();
+
+	/*The close of the inode*/
+	void Destroy();
+
+	/*Send the pBuffer(which is an ip[ packet)
+	 *after adding the header to the packet.*/
+	int  AddHeaderAndSend(
+			unsigned char *pBuffer,
+			size_t nIPPacketSize);
+
+	/*Send raw data as is - no header removal
+	 *- nBytesToSend bytes will be added*/
+	int Send(
+			unsigned char *pBuffer,
+			size_t nBytesToSend);
+
+	/*Receive data from the IPA and remove its header*/
+	int  ReceiveAndRemoveHeader(
+			unsigned char *pBuffer,
+			size_t nIPPacketSize);
+
+	/*Receive data from the IPA as is*/
+	int  Receive(unsigned char *pBuffer, size_t nBytesToReceive);
+
+	/*return the Client type of this pipe.*/
+	enum ipa_client_type  GetClientType();
+
+	/*Return the length of the header to be added to an
+	 *IP packet before it is being sent to the pipe
+	 *(This length will be determine by the Pipe's ClientType).
+	 */
+	int  GetHeaderLengthAdd();
+
+	/*Return the length of the header to be removed from a
+	 *packet before it is being sent to the user
+	 *(thus returning only the IP packet).
+	 *(This length will be determine by the Pipe's ClientType).
+	 */
+	int  GetHeaderLengthRemove();
+
+	bool EnableHolb(unsigned timerValue);
+	bool DisableHolb();
+
+private:
+	void SetSpecificClientParameters(
+			enum ipa_client_type nClientType,
+			IPATestConfiguration eConfiguration);
+
+	bool ConfigureHolb(unsigned short enable, unsigned timerValue);
+
+public:
+	/*efault Headers(Can be changed in Derived classes).*/
+	static unsigned char m_pUsbHeader[];
+	static unsigned char m_pHSICHeader[];
+	static unsigned char m_pA2DUNHeader[];
+	static unsigned char m_pA2NDUNHeader[];
+	static unsigned char m_pQ6LANHeader[];
+
+
+private:
+	int         m_Fd;
+	/*The file descriptor which will be used to transfer data
+	 * via the inode(this inode will be created by the ITAKEM)
+	 */
+	enum ipa_client_type  m_nClientType;
+	int         m_nHeaderLengthRemove;
+	/*this length will be set in the
+	 * constructor in corresponds to m_nClientType
+	 */
+	int         m_nHeaderLengthAdd;
+	/*this length will be set in the constructor
+	 * in corresponds to m_nClientType
+	 */
+	unsigned char       *m_pHeader;
+	/*this pointer will be set to the current pipe used*/
+	const char *m_pInodePath;
+	/*this pointer will be set to the current pipe used*/
+	bool        m_bInitialized;
+	IPATestConfiguration m_eConfiguration;
+	/*The Pipes configuration env*/
+	bool m_ExceptionPipe;
+	/* Is this the exception pipe */
+
+};
+
+#endif

+ 107 - 0
kernel-tests/PipeTestFixture.cpp

@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PipeTestFixture.h"
+
+extern Logger g_Logger;
+
+/*define the static Pipes which will be used by all derived tests.*/
+Pipe PipeTestFixture::m_IpaToUsbPipe(IPA_CLIENT_TEST_CONS, IPA_TEST_CONFIFURATION_1);
+Pipe PipeTestFixture::m_UsbToIpaPipe(IPA_CLIENT_TEST_PROD, IPA_TEST_CONFIFURATION_1);
+
+PipeTestFixture::PipeTestFixture()
+{
+	m_testSuiteName.push_back("Pipes");
+	Register(*this);
+}
+
+static int SetupKernelModule(void)
+{
+	int retval;
+	struct ipa_channel_config from_ipa_0 = {0};
+	struct test_ipa_ep_cfg from_ipa_0_cfg;
+	struct ipa_channel_config to_ipa_0 = {0};
+	struct test_ipa_ep_cfg to_ipa_0_cfg;
+
+	struct ipa_test_config_header header = {0};
+	struct ipa_channel_config *to_ipa_array[1];
+	struct ipa_channel_config *from_ipa_array[1];
+
+
+	/* From ipa configurations - 1 pipes */
+	memset(&from_ipa_0_cfg, 0 , sizeof(from_ipa_0_cfg));
+	prepare_channel_struct(&from_ipa_0,
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST_CONS,
+			(void *)&from_ipa_0_cfg,
+			sizeof(from_ipa_0_cfg));
+	from_ipa_array[0] = &from_ipa_0;
+
+	/* To ipa configurations - 1 pipes */
+	memset(&to_ipa_0_cfg, 0 , sizeof(to_ipa_0_cfg));
+	to_ipa_0_cfg.mode.mode = IPA_DMA;
+	to_ipa_0_cfg.mode.dst = IPA_CLIENT_TEST_CONS;
+	prepare_channel_struct(&to_ipa_0,
+			header.to_ipa_channels_num++,
+			IPA_CLIENT_TEST_PROD,
+			(void *)&to_ipa_0_cfg,
+			sizeof(to_ipa_0_cfg));
+	to_ipa_array[0] = &to_ipa_0;
+
+	prepare_header_struct(&header, from_ipa_array, to_ipa_array);
+
+	retval = GenericConfigureScenario(&header);
+
+	return retval;
+}
+
+bool PipeTestFixture::Setup()
+{
+	bool bRetVal = true;
+
+	if (SetupKernelModule() == false)
+		return false;
+
+	/*Initialize the pipe for all the tests -
+	 * this will open the inode which represents the pipe.
+	 */
+	bRetVal &= m_IpaToUsbPipe.Init();
+	bRetVal &= m_UsbToIpaPipe.Init();
+
+	return bRetVal;
+}
+
+bool PipeTestFixture::Teardown()
+{
+	/*The Destroy method will close the inode.*/
+	m_IpaToUsbPipe.Destroy();
+	m_UsbToIpaPipe.Destroy();
+
+	return true;
+}

+ 69 - 0
kernel-tests/PipeTestFixture.h

@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "Constants.h"
+#include "Logger.h"
+#include "linux/msm_ipa.h"
+#include "TestsUtils.h"
+#include "TestBase.h"
+#include "Pipe.h"
+
+/*This class will be the base class of all Pipe tests.
+ *Any method other than the test case itself can be
+ *declared in this Fixture thus allowing the derived classes to
+ *implement only the test case.
+ *All the test of the pipe uses one input and one output in DMA mode.
+ */
+class PipeTestFixture:public TestBase
+{
+public:
+	/*This Constructor will register each instance that it creates.*/
+	PipeTestFixture();
+
+	/*This method will create and initialize two Pipe object for the USB
+	 * (Ethernet) Pipes, one as input and the other as output.
+	 */
+	virtual bool Setup();
+
+	/*This method will destroy the pipes.*/
+	virtual bool Teardown();
+
+	/*The client type are set from the peripheral perspective
+	 * (TODO Pipe:in case the Driver will change its perspective
+	 * of ipa_connect this should be changed).
+	 */
+	static Pipe m_IpaToUsbPipe;
+	static Pipe m_UsbToIpaPipe;
+};

+ 478 - 0
kernel-tests/PipeTests.cpp

@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "PipeTestFixture.h"
+#include "Constants.h"
+#include "TestsUtils.h"
+#include "linux/msm_ipa.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class PipeTestRawTransfer: public PipeTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	PipeTestRawTransfer() {
+		m_name = "PipeTestRawTransfer";
+		m_description = "This test will be using the Pipe raw transfer ability";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool Run() {
+		bool bTestResult = true;
+		Byte pIpPacket[] = { 0x01, 0x02, 0x03, 0x04 }; //This packet will be sent(It can be replaced by a real IP packet).
+		Byte pIpPacketReceive[sizeof(pIpPacket)] = { 0 }; //This buffer will be used in order to store the received packet.
+
+		//Send the raw IP packet(which is a 4 arbitrary bytes) without header addition by the Pipe
+		LOG_MSG_DEBUG(
+				"Sending packet into the USB pipe(%d bytes)\n", sizeof(pIpPacket));
+		int nBytesSent = m_UsbToIpaPipe.Send(pIpPacket, sizeof(pIpPacket));
+		if (sizeof(pIpPacket) != nBytesSent) {
+			return false;
+		}
+
+		//Receive the raw IP packet(which is a 4 arbitrary bytes) without header removal by the Pipe
+		LOG_MSG_DEBUG(
+				"Reading packet from the USB pipe(%d bytes should be there)\n", sizeof(pIpPacketReceive));
+		int nBytesReceived = m_IpaToUsbPipe.Receive(pIpPacketReceive,
+				sizeof(pIpPacketReceive));
+		if (sizeof(pIpPacketReceive) != nBytesReceived) {
+			return false;
+		}
+		for (int i = 0; i < nBytesReceived; i++) {
+			LOG_MSG_DEBUG("0x%02x\n", pIpPacketReceive[i]);
+		}
+
+		//Check that the sent IP packet is equal to the received IP packet.
+		LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+		bTestResult &= !memcmp(pIpPacket, pIpPacketReceive, sizeof(pIpPacket));
+
+		return bTestResult;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+//This test will be using the Pipe Add-Header transfer ability(and not header insertion
+class PipeTestAddHeader: public PipeTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	PipeTestAddHeader() {
+		m_name = "PipeTestAddHeader";
+		m_description = "Add header to USB pipe and receive it without removing the header";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool Run() {
+		Byte pIpPacketSend[4] = { 0x01, 0x02, 0x03, 0x04 };
+		int nReceivedPacketSize = sizeof(pIpPacketSend)
+				+ m_IpaToUsbPipe.GetHeaderLengthAdd();
+		Byte *pPacketReceive = new Byte[nReceivedPacketSize];
+
+		LOG_MSG_DEBUG("Sending packet into the USB pipe(%d bytes - no header size)\n", sizeof(pIpPacketSend));
+		int nRetValSend = m_UsbToIpaPipe.AddHeaderAndSend(pIpPacketSend,
+				sizeof(pIpPacketSend));
+		LOG_MSG_DEBUG("Result of AddHeaderAndSend = %d\n", nRetValSend);
+
+		LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes - including header)\n", nReceivedPacketSize);
+		int nRetValReceive = m_IpaToUsbPipe.Receive(pPacketReceive,
+				nReceivedPacketSize);
+		LOG_MSG_DEBUG("Result of Receive = %d\n", nRetValReceive);
+
+		if (nReceivedPacketSize != nRetValReceive) {
+			delete[] pPacketReceive;
+			LOG_MSG_ERROR(
+					"Size of received packet is not as expected - %d\n", nRetValReceive);
+			return false;
+		}
+
+		bool bHeaderCmp = !memcmp(pPacketReceive, Pipe::m_pUsbHeader,
+				m_IpaToUsbPipe.GetHeaderLengthAdd());
+		LOG_MSG_DEBUG("bHeaderCmp - %s\n", bHeaderCmp ? "True" : "False");
+
+		bool bIpCmp = !memcmp(pPacketReceive + m_IpaToUsbPipe.GetHeaderLengthAdd(),
+				pIpPacketSend, sizeof(pIpPacketSend));
+		LOG_MSG_DEBUG("bIpCmp - %s\n", bIpCmp ? "True" : "False");
+
+		delete[] pPacketReceive;
+		return bHeaderCmp && bIpCmp;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+//This test will be using the Pipe Remove-Header transfer ability(and header addition)
+class PipeTestAddAndRemoveHeader: public PipeTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	PipeTestAddAndRemoveHeader() {
+		m_name = "PipeTestAddAndRemoveHeader";
+		m_description = "This test will be using the Pipe Remove-Header transfer ability(and header addition)";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool Run() {
+		Byte pIpPacketSend[4] = { 0x01, 0x02, 0x03, 0x04 };
+		int nToBeReceivedPacketSize = sizeof(pIpPacketSend)
+				+ m_IpaToUsbPipe.GetHeaderLengthAdd();
+		Byte *pPacketReceive = new Byte[nToBeReceivedPacketSize];
+
+		LOG_MSG_DEBUG("Sending packet into the USB pipe(%d bytes - no header size)\n", sizeof(pIpPacketSend));
+		int nBytesSent = m_UsbToIpaPipe.AddHeaderAndSend(pIpPacketSend,
+				sizeof(pIpPacketSend));
+		LOG_MSG_DEBUG("nBytesSent of AddHeaderAndSend = %d\n", nBytesSent);
+
+		LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes - including header)\n", nToBeReceivedPacketSize);
+		int nBytesReceived = m_IpaToUsbPipe.Receive(pPacketReceive,
+				nToBeReceivedPacketSize);
+		LOG_MSG_DEBUG("nBytesReceived = %d\n", nBytesReceived);
+
+		if (nToBeReceivedPacketSize != nBytesReceived) {
+			delete[] pPacketReceive;
+			LOG_MSG_ERROR("Size of received packet is not as expected - %d\n", nBytesReceived);
+			return false;
+		}
+
+		bool bHeaderCmp = !memcmp(pPacketReceive, Pipe::m_pUsbHeader,
+				m_IpaToUsbPipe.GetHeaderLengthAdd());
+		LOG_MSG_DEBUG("bHeaderCmp - %s\n", bHeaderCmp ? "True" : "False");
+
+		bool bIpCmp = !memcmp(pPacketReceive + m_IpaToUsbPipe.GetHeaderLengthAdd(),
+				pIpPacketSend, sizeof(pIpPacketSend));
+		LOG_MSG_DEBUG("bIpCmp - %s\n", bIpCmp ? "True" : "False");
+
+		delete[] pPacketReceive;
+		return bHeaderCmp && bIpCmp;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+//This test will try to send big chuck of data and check if the Data FIFO is working correct
+class PipeTestDataFifoOverflow: public PipeTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	PipeTestDataFifoOverflow() {
+		m_name = "PipeTestDataFifoOverflow";
+		m_description = "Send many big packets over the IPA. there will be toggle of send/receive";
+		m_runInRegression = false; // Test is very long thus makes a problem in regression testing
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool Run() {
+		bool bTestResult = true;
+		int nPacketByteSize;
+		int nTotalDataSent = 0;
+		int nTestsMaxDataSend = 3 * 0x6400;
+		int nIterationNumber = 0;
+		Byte *pIpPacket;
+		Byte *pIpPacketReceive;
+		srand(123); //set some constant seed value in order to be able to reproduce problems.
+
+		//send and receive many packets(nIterations)
+		while (nTotalDataSent < nTestsMaxDataSend) {
+			//get random values for this packet.
+			nPacketByteSize = (rand() % 400) + 200;
+			pIpPacket = new Byte[nPacketByteSize];
+
+			for (int j = 0; j < nPacketByteSize; j++) {
+				pIpPacket[j] = rand() % 0x100;
+			}
+
+			//Send the raw IP packet(which is a 4 arbitrary bytes) without header addition by the Pipe
+			LOG_MSG_DEBUG(
+					"Iteration number %d(0x%08x/0x%08x data):\n", nIterationNumber++, nTotalDataSent, nTestsMaxDataSend);
+			LOG_MSG_DEBUG(
+					"Sending packet into the USB pipe(%d bytes)\n", nPacketByteSize);
+			int nBytesSent = m_UsbToIpaPipe.Send(pIpPacket, nPacketByteSize);
+			if (nPacketByteSize != nBytesSent) {
+				delete[] pIpPacket;
+				LOG_MSG_ERROR("Could not send the whole packet - nTotalDataSent = 0x%08x\n", nTotalDataSent);
+				return false;
+			}
+
+			//Receive the raw IP packet(which is a 4 arbitrary bytes) without header removal by the Pipe
+			pIpPacketReceive = new Byte[nPacketByteSize];
+			LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be there)\n", nPacketByteSize);
+			int nBytesReceived = m_IpaToUsbPipe.Receive(pIpPacketReceive,
+					nPacketByteSize);
+			if (nPacketByteSize != nBytesReceived) {
+				delete[] pIpPacket;
+				delete[] pIpPacketReceive;
+				LOG_MSG_ERROR("Could not read the whole packet - nTotalDataSent = 0x%08x\n", nTotalDataSent);
+				return false;
+			}
+			for (int j = 0; j < nBytesReceived; j++) {
+				LOG_MSG_DEBUG("0x%02x\n", pIpPacketReceive[j]);
+			}
+
+			//Check that the sent IP packet is equal to the received IP packet.
+			LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+			bTestResult &= !memcmp(pIpPacket, pIpPacketReceive,
+					nPacketByteSize);
+			if (true != bTestResult) {
+				delete[] pIpPacketReceive;
+				delete[] pIpPacket;
+				LOG_MSG_ERROR("Send != Received  - nTotalDataSent = 0x%08x\n", nTotalDataSent);
+				return false;
+			}
+			nTotalDataSent += nPacketByteSize;
+			delete[] pIpPacket;
+			delete[] pIpPacketReceive;
+		}
+		LOG_MSG_DEBUG("Great success - nTotalDataSent = 0x%08x\n", nTotalDataSent);
+		return true;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+//This test will try to many little chuck of data and check if the Descriptor FIFO is working correct
+class PipeTestDescriptorFifoOverflow: public PipeTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	PipeTestDescriptorFifoOverflow() {
+		m_name = "PipeTestDescriptorFifoOverflow";
+		m_description = "Send many small packets over the IPA. there will be toggle of send/receive";
+		m_runInRegression = false; // Test is very long thus makes a problem in regression testing
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool Run() {
+		bool bTestResult = true;
+		int nPacketByteSize;
+		int nTotalPacketSent = 0;
+		int nTestsMaxDescriptors = 3 * 0x1000;
+		int nIterationNumber = 0;
+		Byte *pIpPacket;
+		Byte *pIpPacketReceive;
+		srand(123); //set some constant seed value in order to be able to reproduce problems.
+
+		//send and receive many packets(nIterations)
+		while (nTotalPacketSent < nTestsMaxDescriptors) {
+			//get random values for this packet.
+			nPacketByteSize = (rand() % 10) + 1;
+			pIpPacket = new Byte[nPacketByteSize];
+
+			for (int j = 0; j < nPacketByteSize; j++) {
+				pIpPacket[j] = rand() % 0x100;
+			}
+
+			//Send the raw IP packet(which is a 4 arbitrary bytes) without header addition by the Pipe
+			LOG_MSG_DEBUG("Iteration number %d(0x%08x/0x%08x packets):\n", nIterationNumber++, nTotalPacketSent, nTestsMaxDescriptors);
+			LOG_MSG_DEBUG("Sending packet into the USB pipe(%d bytes)\n", nPacketByteSize);
+			int nBytesSent = m_UsbToIpaPipe.Send(pIpPacket, nPacketByteSize);
+			if (nPacketByteSize != nBytesSent) {
+				delete[] pIpPacket;
+				LOG_MSG_ERROR("Could not send the whole packet - nTotalPacketSent = 0x%08x\n", nTotalPacketSent);
+				return false;
+			}
+
+			//Receive the raw IP packet(which is a 4 arbitrary bytes) without header removal by the Pipe
+			pIpPacketReceive = new Byte[nPacketByteSize];
+			LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be there)\n", nPacketByteSize);
+			int nBytesReceived = m_IpaToUsbPipe.Receive(pIpPacketReceive,
+					nPacketByteSize);
+			if (nPacketByteSize != nBytesReceived) {
+				delete[] pIpPacketReceive;
+				LOG_MSG_ERROR("Could not read the whole packet - nTotalPacketSent = 0x%08x\n", nTotalPacketSent);
+				return false;
+			}
+			for (int j = 0; j < nBytesReceived; j++) {
+				LOG_MSG_DEBUG("0x%02x\n", pIpPacketReceive[j]);
+			}
+
+			//Check that the sent IP packet is equal to the received IP packet.
+			LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+			bTestResult &= !memcmp(pIpPacket, pIpPacketReceive,
+					nPacketByteSize);
+			if (true != bTestResult) {
+				delete[] pIpPacketReceive;
+				delete[] pIpPacket;
+				LOG_MSG_ERROR("Send != Received  - nTotalPacketSent = 0x%08x\n", nTotalPacketSent);
+				return false;
+			}
+			nTotalPacketSent++;
+			delete[] pIpPacket;
+			delete[] pIpPacketReceive;
+		}
+		LOG_MSG_DEBUG("Great success - nTotalPacketSent = 0x%08x\n", nTotalPacketSent);
+		return true;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+#define HOLB_TEST_PACKETS_MAX_NUM 50
+class PipeTestHolb: public PipeTestFixture {
+
+public:
+
+	PipeTestHolb() {
+		m_name = "PipeTestHolb";
+		m_description = "This test will check the HOLB function";
+	}
+
+	bool Run() {
+		int nPacketsToSend = HOLB_TEST_PACKETS_MAX_NUM;
+		int nBytesReceived;
+		int nBytesSentInLastPacket;
+		int i;
+		Byte pIpPacket[] = { 0x01, 0x02, 0x03, 0x04 }; //This packet will be sent(It can be replaced by a real IP packet).
+		Byte pIpPacketReceive[sizeof(pIpPacket) * HOLB_TEST_PACKETS_MAX_NUM] = { 0 }; //This buffer will be used in order to store the received packet.
+
+		m_IpaToUsbPipe.DisableHolb();
+
+		//Send the IP packets
+		LOG_MSG_DEBUG("Sending %d packets of %d bytes into the USB pipe\n",
+					  nPacketsToSend, sizeof(pIpPacket));
+		for (i = 0; i < nPacketsToSend; i++) {
+			nBytesSentInLastPacket = m_UsbToIpaPipe.Send(pIpPacket, sizeof(pIpPacket));
+			if (sizeof(pIpPacket) != nBytesSentInLastPacket) {
+				LOG_MSG_ERROR("Failed sending the packet %d to m_UsbToIpaPipe", i);
+				return false;
+			}
+		}
+
+		//Receive all the raw IP packets (which are a 4 arbitrary bytes)
+		LOG_MSG_DEBUG(
+				"Reading packets from the USB pipe (%dx%d bytes should be there)\n",
+				sizeof(pIpPacket), nPacketsToSend);
+		for (i = 0; i < nPacketsToSend; i++) {
+			nBytesReceived = m_IpaToUsbPipe.Receive(pIpPacketReceive, sizeof(pIpPacketReceive));
+			if ((int)sizeof(pIpPacket) != nBytesReceived) {
+				LOG_MSG_ERROR("Failed with HOLB disabled! Packet #%d: Expected %d Bytes, got %d Bytes",
+							  i, sizeof(pIpPacket), nBytesReceived);
+				return false;
+			}
+		}
+
+		// Enable HOLB
+		m_IpaToUsbPipe.EnableHolb(0);
+
+		//Send the IP packets
+		LOG_MSG_DEBUG("Sending %d packets of %d bytes into the USB pipe\n",
+					  nPacketsToSend, sizeof(pIpPacket));
+		for (i = 0; i < nPacketsToSend; i++) {
+			nBytesSentInLastPacket = m_UsbToIpaPipe.Send(pIpPacket, sizeof(pIpPacket));
+			if (sizeof(pIpPacket) != nBytesSentInLastPacket) {
+				LOG_MSG_ERROR("Failed sending the packet %d to m_UsbToIpaPipe", i);
+				return false;
+			}
+		}
+
+		// Receive the raw IP packets (which are a 4 arbitrary bytes)
+		// that fit into the FIFO before the HOLB started dropping
+		// and fail to receive the rest
+		LOG_MSG_DEBUG(
+				"Reading packets from the USB pipe(%dx%d bytes should be there)\n",
+				sizeof(pIpPacket), nPacketsToSend);
+		for (i = 0; i < nPacketsToSend; i++) {
+			int nBytesReceived = m_IpaToUsbPipe.Receive(pIpPacketReceive,
+					sizeof(pIpPacketReceive));
+			if ((int)sizeof(pIpPacket) != nBytesReceived) {
+				if (i == 0) {
+					LOG_MSG_ERROR("First packet failed to receive ! Expected %d Bytes, got %d Bytes",
+								  sizeof(pIpPacket), nBytesReceived);
+					return false;
+				} else
+					// Failed to receive a packet, but not the first one.
+					// This is the desired result.
+					return true;
+			}
+		}
+
+		LOG_MSG_ERROR("All packets were received successfully, which means the HOLB didn't work.");
+		return false;
+	}
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+//Those tests should be run with configuration number 1 which has one input pipe and
+//one output pipe.
+//Please look at the Fixture for more configurations update.
+static PipeTestRawTransfer pipeTestRawTransfer;
+static PipeTestAddHeader pipeTestAddHeader;
+static PipeTestAddAndRemoveHeader pipeTestAddAndRemoveHeader;
+static PipeTestHolb pipeTestHolb;
+
+//DO NOT UNCOMMENT THOSE LINES UNLESS YOU KNOW WHAT YOU ARE DOING!!!
+//those test takes 4ever and should be use for specific usecase!
+//static PipeTestDataFifoOverflow pipeTestDataFifoOverflow;
+//static PipeTestDescriptorFifoOverflow pipeTestDescriptorFifoOverflow;
+
+/////////////////////////////////////////////////////////////////////////////////
+//                                  EOF                                      ////
+/////////////////////////////////////////////////////////////////////////////////

+ 11 - 0
kernel-tests/README.txt

@@ -0,0 +1,11 @@
+Subsystem: ipa-kernel-tests
+
+Parameters:
+  -n: Nominal test case (tests all the different use cases for ip_accelerator)
+  -a: Adversarial test case (Currently holds no tests)
+  -r: Repeatability test case (Currently holds no tests)
+  -s: Stress test case (invokes many simultaneous threads that all try and access the device at once)
+  --help: Specifies the params for run.sh
+
+Description:
+This test module tests IPA driver, it holds a userspace module and a kernel space module.

+ 1097 - 0
kernel-tests/RNDISAggregationTestFixture.cpp

@@ -0,0 +1,1097 @@
+/*
+ * Copyright (c) 2017-2018,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "RNDISAggregationTestFixture.h"
+#include "TestManager.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+
+//define the static Pipes which will be used by all derived tests.
+Pipe RNDISAggregationTestFixture::m_IpaToUsbPipeAgg(IPA_CLIENT_TEST2_CONS,
+							 IPA_TEST_CONFIGURATION_17);
+Pipe RNDISAggregationTestFixture::m_UsbToIpaPipe(IPA_CLIENT_TEST_PROD,
+						      IPA_TEST_CONFIGURATION_17);
+Pipe RNDISAggregationTestFixture::m_IpaToUsbPipe(IPA_CLIENT_TEST3_CONS,
+						      IPA_TEST_CONFIGURATION_17);
+Pipe RNDISAggregationTestFixture::m_UsbToIpaPipeDeagg(IPA_CLIENT_TEST2_PROD,
+							   IPA_TEST_CONFIGURATION_17);
+Pipe RNDISAggregationTestFixture::m_IpaToUsbPipeAggTime(IPA_CLIENT_TEST_CONS,
+							     IPA_TEST_CONFIGURATION_17);
+Pipe RNDISAggregationTestFixture::m_IpaToUsbPipeAggPktLimit(IPA_CLIENT_TEST4_CONS,
+								IPA_TEST_CONFIGURATION_17);
+Pipe RNDISAggregationTestFixture::m_HsicToIpaPipe(IPA_CLIENT_TEST3_PROD,
+							   IPA_TEST_CONFIGURATION_17);
+
+RoutingDriverWrapper RNDISAggregationTestFixture::m_Routing;
+Filtering RNDISAggregationTestFixture::m_Filtering;
+HeaderInsertion RNDISAggregationTestFixture::m_HeaderInsertion;
+
+/////////////////////////////////////////////////////////////////////////////////
+
+RNDISAggregationTestFixture::RNDISAggregationTestFixture()
+{
+	m_testSuiteName.push_back("RndisAgg");
+	Register(*this);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+static int SetupKernelModule(void)
+{
+	int retval;
+	struct ipa_channel_config from_ipa_channels[4];
+	struct test_ipa_ep_cfg from_ipa_cfg[4];
+	struct ipa_channel_config to_ipa_channels[3];
+	struct test_ipa_ep_cfg to_ipa_cfg[3];
+	struct ipa_test_config_header header = {0};
+	struct ipa_channel_config *to_ipa_array[3];
+	struct ipa_channel_config *from_ipa_array[4];
+	bool en_status = false;
+
+	/* From ipa configurations - 4 pipes */
+	memset(&from_ipa_cfg[0], 0, sizeof(from_ipa_cfg[0]));
+	from_ipa_cfg[0].aggr.aggr_en = IPA_ENABLE_AGGR;
+	from_ipa_cfg[0].aggr.aggr = IPA_GENERIC;
+	from_ipa_cfg[0].aggr.aggr_byte_limit = 1;
+	from_ipa_cfg[0].aggr.aggr_time_limit = 0;
+	from_ipa_cfg[0].hdr.hdr_ofst_pkt_size_valid = true;
+	from_ipa_cfg[0].hdr.hdr_ofst_pkt_size = 12;
+	from_ipa_cfg[0].hdr.hdr_additional_const_len = 14;
+	from_ipa_cfg[0].hdr.hdr_len = 58;
+	from_ipa_cfg[0].hdr_ext.hdr_little_endian = true;
+	from_ipa_cfg[0].hdr_ext.hdr_total_len_or_pad_valid = true;
+	from_ipa_cfg[0].hdr_ext.hdr_total_len_or_pad = IPA_HDR_TOTAL_LEN;
+	from_ipa_cfg[0].hdr_ext.hdr_total_len_or_pad_offset = 4;
+
+	prepare_channel_struct(&from_ipa_channels[0],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST2_CONS,
+			(void *)&from_ipa_cfg[0],
+			sizeof(from_ipa_cfg[0]),
+			en_status);
+	from_ipa_array[0] = &from_ipa_channels[0];
+
+	memset(&from_ipa_cfg[1], 0, sizeof(from_ipa_cfg[1]));
+	prepare_channel_struct(&from_ipa_channels[1],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST3_CONS,
+			(void *)&from_ipa_cfg[1],
+			sizeof(from_ipa_cfg[1]),
+			en_status);
+	from_ipa_array[1] = &from_ipa_channels[1];
+
+	memset(&from_ipa_cfg[2], 0, sizeof(from_ipa_cfg[2]));
+	from_ipa_cfg[2].aggr.aggr_en = IPA_ENABLE_AGGR;
+	from_ipa_cfg[2].aggr.aggr = IPA_GENERIC;
+	from_ipa_cfg[2].aggr.aggr_byte_limit = 1;
+	from_ipa_cfg[2].aggr.aggr_time_limit = 30;
+	if (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v4_2)
+		from_ipa_cfg[2].aggr.aggr_time_limit *= 1000;
+	from_ipa_cfg[2].hdr.hdr_ofst_pkt_size_valid = true;
+	from_ipa_cfg[2].hdr.hdr_ofst_pkt_size = 12;
+	from_ipa_cfg[2].hdr.hdr_additional_const_len = 14;
+	from_ipa_cfg[2].hdr.hdr_len = 58;
+	from_ipa_cfg[2].hdr_ext.hdr_little_endian = true;
+	from_ipa_cfg[2].hdr_ext.hdr_total_len_or_pad_valid = true;
+	from_ipa_cfg[2].hdr_ext.hdr_total_len_or_pad = IPA_HDR_TOTAL_LEN;
+	from_ipa_cfg[2].hdr_ext.hdr_total_len_or_pad_offset = 4;
+
+	prepare_channel_struct(&from_ipa_channels[2],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST_CONS,
+			(void *)&from_ipa_cfg[2],
+			sizeof(from_ipa_cfg[2]),
+			en_status);
+	from_ipa_array[2] = &from_ipa_channels[2];
+
+	memset(&from_ipa_cfg[3], 0, sizeof(from_ipa_cfg[3]));
+	from_ipa_cfg[3].aggr.aggr_en = IPA_ENABLE_AGGR;
+	from_ipa_cfg[3].aggr.aggr = IPA_GENERIC;
+	from_ipa_cfg[3].aggr.aggr_byte_limit = 0;
+	from_ipa_cfg[3].aggr.aggr_time_limit = 0;
+	from_ipa_cfg[3].aggr.aggr_pkt_limit = 2;
+	from_ipa_cfg[3].hdr.hdr_ofst_pkt_size_valid = true;
+	from_ipa_cfg[3].hdr.hdr_ofst_pkt_size = 12;
+	from_ipa_cfg[3].hdr.hdr_additional_const_len = 14;
+	from_ipa_cfg[3].hdr.hdr_len = 58;
+	from_ipa_cfg[3].hdr_ext.hdr_little_endian = true;
+	from_ipa_cfg[3].hdr_ext.hdr_total_len_or_pad_valid = true;
+	from_ipa_cfg[3].hdr_ext.hdr_total_len_or_pad = IPA_HDR_TOTAL_LEN;
+	from_ipa_cfg[3].hdr_ext.hdr_total_len_or_pad_offset = 4;
+
+	prepare_channel_struct(&from_ipa_channels[3],
+			header.from_ipa_channels_num++,
+			IPA_CLIENT_TEST4_CONS,
+			(void *)&from_ipa_cfg[3],
+			sizeof(from_ipa_cfg[3]),
+			en_status);
+	from_ipa_array[3] = &from_ipa_channels[3];
+
+	/* to ipa configurations - 3 pipes */
+	memset(&to_ipa_cfg[0], 0, sizeof(to_ipa_cfg[0]));
+	to_ipa_cfg[0].hdr.hdr_len = 14;
+
+	prepare_channel_struct(&to_ipa_channels[0],
+			header.to_ipa_channels_num++,
+			IPA_CLIENT_TEST_PROD,
+			(void *)&to_ipa_cfg[0],
+			sizeof(to_ipa_cfg[0]),
+			en_status);
+	to_ipa_array[0] = &to_ipa_channels[0];
+
+	memset(&to_ipa_cfg[1], 0, sizeof(to_ipa_cfg[1]));
+	prepare_channel_struct(&to_ipa_channels[1],
+			header.to_ipa_channels_num++,
+			IPA_CLIENT_TEST3_PROD,
+			(void *)&to_ipa_cfg[1],
+			sizeof(to_ipa_cfg[1]),
+			en_status);
+	to_ipa_array[1] = &to_ipa_channels[1];
+
+	memset(&to_ipa_cfg[2], 0, sizeof(to_ipa_cfg[2]));
+	to_ipa_cfg[2].aggr.aggr_en = IPA_ENABLE_DEAGGR;
+	to_ipa_cfg[2].aggr.aggr = IPA_GENERIC;
+	to_ipa_cfg[2].deaggr.deaggr_hdr_len = 44;
+	to_ipa_cfg[2].deaggr.packet_offset_valid = true;
+	to_ipa_cfg[2].deaggr.packet_offset_location = 8;
+	to_ipa_cfg[2].hdr.hdr_len = 14; /* Ethernet header */
+	to_ipa_cfg[2].hdr.hdr_ofst_pkt_size = 12;
+	to_ipa_cfg[2].hdr.hdr_remove_additional = false;
+	to_ipa_cfg[2].hdr_ext.hdr_little_endian = 1;
+	to_ipa_cfg[2].hdr_ext.hdr_total_len_or_pad_valid = 1;
+	to_ipa_cfg[2].hdr_ext.hdr_total_len_or_pad = IPA_HDR_TOTAL_LEN;
+	to_ipa_cfg[2].hdr_ext.hdr_payload_len_inc_padding = 0;
+	to_ipa_cfg[2].hdr_ext.hdr_total_len_or_pad_offset = 4;
+
+	prepare_channel_struct(&to_ipa_channels[2],
+			header.to_ipa_channels_num++,
+			IPA_CLIENT_TEST2_PROD,
+			(void *)&to_ipa_cfg[2],
+			sizeof(to_ipa_cfg[2]),
+			en_status);
+	to_ipa_array[2] = &to_ipa_channels[2];
+
+	prepare_header_struct(&header, from_ipa_array, to_ipa_array);
+
+	retval = GenericConfigureScenario(&header);
+
+	return retval;
+}
+
+bool RNDISAggregationTestFixture::Setup()
+{
+	bool bRetVal = true;
+
+	//Set the configuration to support USB->IPA and IPA->USB pipes.
+	bRetVal = SetupKernelModule();
+	if (bRetVal != true) {
+		return bRetVal;
+	}
+
+	//Initialize the pipe for all the tests - this will open the inode which represents the pipe.
+	bRetVal &= m_IpaToUsbPipeAgg.Init();
+	bRetVal &= m_UsbToIpaPipe.Init();
+	bRetVal &= m_HsicToIpaPipe.Init();
+	bRetVal &= m_IpaToUsbPipe.Init();
+	bRetVal &= m_UsbToIpaPipeDeagg.Init();
+	bRetVal &= m_IpaToUsbPipeAggTime.Init();
+	bRetVal &= m_IpaToUsbPipeAggPktLimit.Init();
+
+	if (!m_Routing.DeviceNodeIsOpened()) {
+		LOG_MSG_ERROR(
+			"Routing block is not ready for immediate commands!\n");
+		return false;
+	}
+	if (!m_Filtering.DeviceNodeIsOpened()) {
+		LOG_MSG_ERROR(
+			"Filtering block is not ready for immediate commands!\n");
+		return false;
+	}
+	if (!m_HeaderInsertion.DeviceNodeIsOpened())
+	{
+		LOG_MSG_ERROR("Header Insertion block is not ready for immediate commands!\n");
+		return false;
+	}
+	m_HeaderInsertion.Reset();// resetting this component will reset both Routing and Filtering tables.
+
+	return bRetVal;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool RNDISAggregationTestFixture::Teardown()
+{
+	//The Destroy method will close the inode.
+	m_IpaToUsbPipeAgg.Destroy();
+	m_UsbToIpaPipe.Destroy();
+	m_HsicToIpaPipe.Destroy();
+	m_IpaToUsbPipe.Destroy();
+	m_UsbToIpaPipeDeagg.Destroy();
+	m_IpaToUsbPipeAggTime.Destroy();
+	m_IpaToUsbPipeAggPktLimit.Destroy();
+
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool RNDISAggregationTestFixture::Run()
+{
+	LOG_MSG_STACK("Entering Function");
+
+	// Add the relevant filtering rules
+	if (!AddRules()) {
+		LOG_MSG_ERROR("Failed adding filtering rules.");
+		return false;
+	}
+	if (!TestLogic()) {
+		LOG_MSG_ERROR("Test failed, Input and expected output mismatch.");
+		return false;
+	}
+
+	LOG_MSG_STACK("Leaving Function (Returning True)");
+	return true;
+} // Run()
+
+/////////////////////////////////////////////////////////////////////////////////
+bool RNDISAggregationTestFixture::AddRulesNoAgg() {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[20] = "Bypass1";
+	bool bRetVal = true;
+	IPAFilteringTable cFilterTable0;
+	struct ipa_flt_rule_add sFilterRuleEntry;
+	uint32_t nTableHdl;
+
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+
+	if (!CreateBypassRoutingTable(&m_Routing, m_eIP, aBypass, IPA_CLIENT_TEST3_CONS,
+			0, &nTableHdl)) {
+		LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+		bRetVal = false;
+		goto bail;
+	}
+
+
+	LOG_MSG_INFO("Creation of bypass routing table completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST_PROD, false, 1);
+	LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.retain_hdr = true;
+	sFilterRuleEntry.rule.rt_tbl_hdl = nTableHdl; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	if (
+			((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+			!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+bail:
+	LOG_MSG_STACK(
+			"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRules()
+
+bool RNDISAggregationTestFixture::AddRulesDeAggEther() {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[20] = "Bypass1";
+	bool bRetVal = true;
+	IPAFilteringTable cFilterTable0;
+	struct ipa_flt_rule_add sFilterRuleEntry;
+	uint32_t nTableHdl;
+
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+
+	if (!CreateBypassRoutingTable(&m_Routing, m_eIP, aBypass, IPA_CLIENT_TEST3_CONS,
+			0, &nTableHdl)) {
+		LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+		bRetVal = false;
+		goto bail;
+	}
+
+
+	LOG_MSG_INFO("Creation of bypass routing table completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST2_PROD, false, 1);
+	LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.retain_hdr = true;
+	sFilterRuleEntry.rule.rt_tbl_hdl = nTableHdl; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	if (
+			((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+			!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+bail:
+	LOG_MSG_STACK(
+			"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRules()
+
+bool RNDISAggregationTestFixture::AddRulesAggTimeLimit() {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[20] = "Bypass1";
+	bool bRetVal = true;
+	IPAFilteringTable cFilterTable0;
+	struct ipa_flt_rule_add sFilterRuleEntry;
+	struct ipa_ioc_get_hdr sGetHeader;
+	uint32_t nTableHdl;
+	struct RndisEtherHeader rndisEtherHeader;
+
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+	memset(&sGetHeader, 0, sizeof(sGetHeader));
+	memset(&rndisEtherHeader, 0, sizeof(struct RndisEtherHeader));
+	rndisEtherHeader.rndisHeader.MessageType = 0x01;
+	rndisEtherHeader.rndisHeader.DataOffset = 0x24;
+	memcpy(&rndisEtherHeader.etherHeader, Eth2Helper::m_ETH2_IP4_HDR, sizeof(struct ethhdr));
+
+	// Create Header:
+	// Allocate Memory, populate it, and add in to the Header Insertion.
+	struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+		sizeof(struct ipa_ioc_add_hdr)
+		+ 1 * sizeof(struct ipa_hdr_add));
+	if (!pHeaderDescriptor) {
+		LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+	// Adding Header No1.
+	strlcpy(pHeaderDescriptor->hdr[0].name, "RndisEthernet", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+	memcpy(pHeaderDescriptor->hdr[0].hdr, (void*)&rndisEtherHeader,
+		sizeof(struct RndisEtherHeader)); //Header's Data
+	pHeaderDescriptor->hdr[0].hdr_len    = sizeof(struct RndisEtherHeader);
+	pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+	pHeaderDescriptor->hdr[0].is_partial = false;
+	pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+	strlcpy(sGetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sGetHeader.name));
+
+
+	if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+	{
+		LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+		bRetVal = false;
+		goto bail;
+	}
+
+	if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader))
+	{
+		LOG_MSG_ERROR(" Failed");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_DEBUG("Received Header Handle = 0x%x", sGetHeader.hdl);
+
+
+	if (!CreateBypassRoutingTable(&m_Routing, m_eIP, aBypass, IPA_CLIENT_TEST_CONS,
+			sGetHeader.hdl, &nTableHdl)) {
+		LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+		bRetVal = false;
+		goto bail;
+	}
+
+
+	LOG_MSG_INFO("Creation of bypass routing table completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST3_PROD, false, 1);
+	LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl = nTableHdl; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	if (
+			((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+			!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+bail:
+	Free(pHeaderDescriptor);
+	LOG_MSG_STACK(
+			"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRules()
+
+bool RNDISAggregationTestFixture::AddRulesAggByteLimit() {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[20] = "Bypass1";
+	bool bRetVal = true;
+	IPAFilteringTable cFilterTable0;
+	struct ipa_flt_rule_add sFilterRuleEntry;
+	struct ipa_ioc_get_hdr sGetHeader;
+	uint32_t nTableHdl;
+	struct RndisEtherHeader rndisEtherHeader;
+
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+	memset(&sGetHeader, 0, sizeof(sGetHeader));
+	memset(&rndisEtherHeader, 0, sizeof(struct RndisEtherHeader));
+
+	rndisEtherHeader.rndisHeader.MessageType = 0x01;
+	rndisEtherHeader.rndisHeader.DataOffset = 0x24;
+	memcpy(&rndisEtherHeader.etherHeader, Eth2Helper::m_ETH2_IP4_HDR, sizeof(struct ethhdr));
+
+	// Create Header:
+	// Allocate Memory, populate it, and add in to the Header Insertion.
+	struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+		sizeof(struct ipa_ioc_add_hdr)
+		+ 1 * sizeof(struct ipa_hdr_add));
+	if (!pHeaderDescriptor) {
+		LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+	// Adding Header No1.
+	strlcpy(pHeaderDescriptor->hdr[0].name, "RndisEthernet", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+	memcpy(pHeaderDescriptor->hdr[0].hdr, (void*)&rndisEtherHeader,
+		sizeof(struct RndisEtherHeader)); //Header's Data
+	pHeaderDescriptor->hdr[0].hdr_len    = sizeof(struct RndisEtherHeader);
+	pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+	pHeaderDescriptor->hdr[0].is_partial = false;
+	pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+	strlcpy(sGetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sGetHeader.name));
+
+
+	if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+	{
+		LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+		bRetVal = false;
+		goto bail;
+	}
+
+	if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader))
+	{
+		LOG_MSG_ERROR(" Failed");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_DEBUG("Received Header Handle = 0x%x", sGetHeader.hdl);
+
+
+	if (!CreateBypassRoutingTable(&m_Routing, m_eIP, aBypass, IPA_CLIENT_TEST2_CONS,
+			sGetHeader.hdl, &nTableHdl)) {
+		LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+		bRetVal = false;
+		goto bail;
+	}
+
+
+	LOG_MSG_INFO("Creation of bypass routing table completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST3_PROD, false, 1);
+	LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl = nTableHdl; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	if (
+			((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+			!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+bail:
+	Free(pHeaderDescriptor);
+	LOG_MSG_STACK(
+			"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRules()
+
+bool RNDISAggregationTestFixture::AddRulesAggByteLimit(bool bAggForceClose) {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[20] = "Bypass1";
+	bool bRetVal = true;
+	IPAFilteringTable_v2 cFilterTable0;
+	struct ipa_flt_rule_add_v2 sFilterRuleEntry;
+	struct ipa_ioc_get_hdr sGetHeader;
+	uint32_t nTableHdl;
+	struct RndisEtherHeader rndisEtherHeader;
+
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+	memset(&sGetHeader, 0, sizeof(sGetHeader));
+	memset(&rndisEtherHeader, 0, sizeof(struct RndisEtherHeader));
+
+	rndisEtherHeader.rndisHeader.MessageType = 0x01;
+	rndisEtherHeader.rndisHeader.DataOffset = 0x24;
+	memcpy(&rndisEtherHeader.etherHeader, Eth2Helper::m_ETH2_IP4_HDR, sizeof(struct ethhdr));
+
+	// Create Header:
+	// Allocate Memory, populate it, and add in to the Header Insertion.
+	struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+		sizeof(struct ipa_ioc_add_hdr)
+		+ 1 * sizeof(struct ipa_hdr_add));
+	if (!pHeaderDescriptor) {
+		LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+	// Adding Header No1.
+	strlcpy(pHeaderDescriptor->hdr[0].name, "RndisEthernet", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+	memcpy(pHeaderDescriptor->hdr[0].hdr, (void*)&rndisEtherHeader,
+		sizeof(struct RndisEtherHeader)); //Header's Data
+	pHeaderDescriptor->hdr[0].hdr_len    = sizeof(struct RndisEtherHeader);
+	pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+	pHeaderDescriptor->hdr[0].is_partial = false;
+	pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+	strlcpy(sGetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sGetHeader.name));
+
+
+	if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+	{
+		LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+		bRetVal = false;
+		goto bail;
+	}
+
+	if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader))
+	{
+		LOG_MSG_ERROR(" Failed");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_DEBUG("Received Header Handle = 0x%x", sGetHeader.hdl);
+
+
+	if (!CreateBypassRoutingTable_v2(&m_Routing, m_eIP, aBypass, IPA_CLIENT_TEST2_CONS,
+			sGetHeader.hdl, &nTableHdl, 0)) {
+		LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+		bRetVal = false;
+		goto bail;
+	}
+
+
+	LOG_MSG_INFO("Creation of bypass routing table completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST3_PROD, false, 1);
+	LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl = nTableHdl; //put here the handle corresponding to Routing Rule 1
+	printf("%s(), Nadav: sFilterRuleEntry.rule.rt_tbl_hdl = %d \n", __FUNCTION__, nTableHdl);
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	sFilterRuleEntry.rule.close_aggr_irq_mod = bAggForceClose;
+	if (
+			((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+			!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+			)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+bail:
+	Free(pHeaderDescriptor);
+	LOG_MSG_STACK(
+			"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRules()
+
+bool RNDISAggregationTestFixture::AddRulesAggPacketLimit() {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[20] = "Bypass1";
+	bool bRetVal = true;
+	IPAFilteringTable cFilterTable0;
+	struct ipa_flt_rule_add sFilterRuleEntry;
+	struct ipa_ioc_get_hdr sGetHeader;
+	uint32_t nTableHdl;
+	struct RndisEtherHeader rndisEtherHeader;
+
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+	memset(&sGetHeader, 0, sizeof(sGetHeader));
+	memset(&rndisEtherHeader, 0, sizeof(struct RndisEtherHeader));
+
+	rndisEtherHeader.rndisHeader.MessageType = 0x01;
+	rndisEtherHeader.rndisHeader.DataOffset = 0x24;
+	memcpy(&rndisEtherHeader.etherHeader, Eth2Helper::m_ETH2_IP4_HDR, sizeof(struct ethhdr));
+
+	// Create Header:
+	// Allocate Memory, populate it, and add in to the Header Insertion.
+	struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+		sizeof(struct ipa_ioc_add_hdr)
+		+ 1 * sizeof(struct ipa_hdr_add));
+	if (!pHeaderDescriptor) {
+		LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+	// Adding Header No1.
+	strlcpy(pHeaderDescriptor->hdr[0].name, "RndisEthernet", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+	memcpy(pHeaderDescriptor->hdr[0].hdr, (void*)&rndisEtherHeader,
+		sizeof(struct RndisEtherHeader)); //Header's Data
+	pHeaderDescriptor->hdr[0].hdr_len    = sizeof(struct RndisEtherHeader);
+	pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+	pHeaderDescriptor->hdr[0].is_partial = false;
+	pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+	strlcpy(sGetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sGetHeader.name));
+
+
+	if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+	{
+		LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+		bRetVal = false;
+		goto bail;
+	}
+
+	if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader))
+	{
+		LOG_MSG_ERROR(" Failed");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_DEBUG("Received Header Handle = 0x%x", sGetHeader.hdl);
+
+
+	if (!CreateBypassRoutingTable(&m_Routing, m_eIP, aBypass, IPA_CLIENT_TEST4_CONS,
+		sGetHeader.hdl, &nTableHdl)) {
+			LOG_MSG_ERROR("CreateBypassRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+	}
+
+
+	LOG_MSG_INFO("Creation of bypass routing table completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST3_PROD, false, 1);
+	LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl = nTableHdl; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	if (
+		((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+		!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+		)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+bail:
+	Free(pHeaderDescriptor);
+	LOG_MSG_STACK(
+		"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRules()
+
+
+
+bool RNDISAggregationTestFixture::AddRulesAggDualFC() {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[2][20] = {"BypassTest2", "BypassTest4"};
+	bool bRetVal = true;
+	IPAFilteringTable_v2 cFilterTable0;
+	struct ipa_flt_rule_add_v2 sFilterRuleEntry;
+	struct ipa_ioc_get_hdr sGetHeader;
+	uint32_t nTableHdl[2];
+	struct RndisEtherHeader rndisEtherHeader;
+
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+	memset(&sGetHeader, 0, sizeof(sGetHeader));
+	memset(&rndisEtherHeader, 0, sizeof(struct RndisEtherHeader));
+
+	rndisEtherHeader.rndisHeader.MessageType = 0x01;
+	rndisEtherHeader.rndisHeader.DataOffset = 0x24;
+	memcpy(&rndisEtherHeader.etherHeader, Eth2Helper::m_ETH2_IP4_HDR, sizeof(struct ethhdr));
+
+	// Create Header:
+	// Allocate Memory, populate it, and add in to the Header Insertion.
+	struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+		sizeof(struct ipa_ioc_add_hdr)
+		+ 1 * sizeof(struct ipa_hdr_add));
+	if (!pHeaderDescriptor) {
+		LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+	// Adding Header No1.
+	strlcpy(pHeaderDescriptor->hdr[0].name, "RndisEthernet", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+	memcpy(pHeaderDescriptor->hdr[0].hdr, (void*)&rndisEtherHeader,
+		sizeof(struct RndisEtherHeader)); //Header's Data
+	pHeaderDescriptor->hdr[0].hdr_len    = sizeof(struct RndisEtherHeader);
+	pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+	pHeaderDescriptor->hdr[0].is_partial = false;
+	pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+	strlcpy(sGetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sGetHeader.name));
+
+
+	if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+	{
+		LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+		bRetVal = false;
+		goto bail;
+	}
+
+	if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader))
+	{
+		LOG_MSG_ERROR(" Failed");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_DEBUG("Received Header Handle = 0x%x", sGetHeader.hdl);
+
+	if (!CreateBypassRoutingTable_v2(&m_Routing, m_eIP, aBypass[0],
+								 IPA_CLIENT_TEST2_CONS,
+								 sGetHeader.hdl, &nTableHdl[0], 0)) {
+			LOG_MSG_ERROR("CreateSplitRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+	}
+
+	if (!CreateBypassRoutingTable_v2(&m_Routing, m_eIP, aBypass[1],
+								 IPA_CLIENT_TEST4_CONS,
+								 sGetHeader.hdl, &nTableHdl[1], 0)) {
+			LOG_MSG_ERROR("CreateSplitRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+	}
+
+	LOG_MSG_INFO("Creation of bypass routing tables completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST3_PROD, false, 2);
+	LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl = nTableHdl[0]; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	sFilterRuleEntry.rule.close_aggr_irq_mod = 1;
+	if (
+		((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+		!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+		)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+	// Configuring Filtering Rule No.2
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl = nTableHdl[1]; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000002; // Filter DST_IP == 127.0.0.1.
+	sFilterRuleEntry.rule.close_aggr_irq_mod = 0;
+	if (
+		((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+		!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+		)
+	{
+		LOG_MSG_ERROR ("Adding Rule (1) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl1=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(1)->status);
+	}
+
+bail:
+	Free(pHeaderDescriptor);
+	LOG_MSG_STACK(
+		"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRulesAggDualFC()
+
+bool RNDISAggregationTestFixture::AddRulesAggDualFcRoutingBased() {
+	m_eIP = IPA_IP_v4;
+	const char aBypass[2][20] = {"BypassTest2", "BypassTest4"};
+	bool bRetVal = true;
+	IPAFilteringTable_v2 cFilterTable0;
+	struct ipa_flt_rule_add_v2 sFilterRuleEntry;
+	struct ipa_ioc_get_hdr sGetHeader;
+	uint32_t nTableHdl[2];
+	struct RndisEtherHeader rndisEtherHeader;
+
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sFilterRuleEntry, 0, sizeof(sFilterRuleEntry));
+	memset(&sGetHeader, 0, sizeof(sGetHeader));
+	memset(&rndisEtherHeader, 0, sizeof(struct RndisEtherHeader));
+
+	rndisEtherHeader.rndisHeader.MessageType = 0x01;
+	rndisEtherHeader.rndisHeader.DataOffset = 0x24;
+	memcpy(&rndisEtherHeader.etherHeader, Eth2Helper::m_ETH2_IP4_HDR, sizeof(struct ethhdr));
+
+	// Create Header:
+	// Allocate Memory, populate it, and add in to the Header Insertion.
+	struct ipa_ioc_add_hdr * pHeaderDescriptor = NULL;
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *) calloc(1,
+		sizeof(struct ipa_ioc_add_hdr)
+		+ 1 * sizeof(struct ipa_hdr_add));
+	if (!pHeaderDescriptor) {
+		LOG_MSG_ERROR("calloc failed to allocate pHeaderDescriptor");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+	// Adding Header No1.
+	strlcpy(pHeaderDescriptor->hdr[0].name, "RndisEthernet", sizeof(pHeaderDescriptor->hdr[0].name)); // Header's Name
+	memcpy(pHeaderDescriptor->hdr[0].hdr, (void*)&rndisEtherHeader,
+		sizeof(struct RndisEtherHeader)); //Header's Data
+	pHeaderDescriptor->hdr[0].hdr_len    = sizeof(struct RndisEtherHeader);
+	pHeaderDescriptor->hdr[0].hdr_hdl    = -1; //Return Value
+	pHeaderDescriptor->hdr[0].is_partial = false;
+	pHeaderDescriptor->hdr[0].status     = -1; // Return Parameter
+
+	strlcpy(sGetHeader.name, pHeaderDescriptor->hdr[0].name, sizeof(sGetHeader.name));
+
+
+	if (!m_HeaderInsertion.AddHeader(pHeaderDescriptor))
+	{
+		LOG_MSG_ERROR("m_HeaderInsertion.AddHeader(pHeaderDescriptor) Failed.");
+		bRetVal = false;
+		goto bail;
+	}
+
+	if (!m_HeaderInsertion.GetHeaderHandle(&sGetHeader))
+	{
+		LOG_MSG_ERROR(" Failed");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_DEBUG("Received Header Handle = 0x%x", sGetHeader.hdl);
+
+	if (!CreateBypassRoutingTable_v2(&m_Routing, m_eIP, aBypass[0],
+								 IPA_CLIENT_TEST2_CONS,
+								 sGetHeader.hdl, &nTableHdl[0], 1)) {
+			LOG_MSG_ERROR("CreateSplitRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+	}
+
+	if (!CreateBypassRoutingTable_v2(&m_Routing, m_eIP, aBypass[1],
+								 IPA_CLIENT_TEST4_CONS,
+								 sGetHeader.hdl, &nTableHdl[1], 0)) {
+			LOG_MSG_ERROR("CreateSplitRoutingTable Failed\n");
+			bRetVal = false;
+			goto bail;
+	}
+
+	LOG_MSG_INFO("Creation of bypass routing tables completed successfully");
+
+	// Creating Filtering Rules
+	cFilterTable0.Init(m_eIP,IPA_CLIENT_TEST3_PROD, false, 2);
+	LOG_MSG_INFO("Creation of filtering table completed successfully");
+
+	// Configuring Filtering Rule No.1
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl = nTableHdl[0]; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000001; // Filter DST_IP == 127.0.0.1.
+	sFilterRuleEntry.rule.close_aggr_irq_mod = 0;
+	if (
+		((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+		!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+		)
+	{
+		LOG_MSG_ERROR ("Adding Rule (0) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl0=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(0)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(0)->status);
+	}
+
+	// Configuring Filtering Rule No.2
+	cFilterTable0.GeneratePresetRule(1,sFilterRuleEntry);
+	sFilterRuleEntry.at_rear = true;
+	sFilterRuleEntry.flt_rule_hdl=-1; // return Value
+	sFilterRuleEntry.status = -1; // return value
+	sFilterRuleEntry.rule.action=IPA_PASS_TO_ROUTING;
+	sFilterRuleEntry.rule.rt_tbl_hdl = nTableHdl[1]; //put here the handle corresponding to Routing Rule 1
+	sFilterRuleEntry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR; // Destination IP Based Filtering
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr_mask = 0xFF0000FF; // Mask
+	sFilterRuleEntry.rule.attrib.u.v4.dst_addr = 0x7F000002; // Filter DST_IP == 127.0.0.1.
+	sFilterRuleEntry.rule.close_aggr_irq_mod = 0;
+	if (
+		((uint8_t)-1 == cFilterTable0.AddRuleToTable(sFilterRuleEntry)) ||
+		!m_Filtering.AddFilteringRule(cFilterTable0.GetFilteringTable())
+		)
+	{
+		LOG_MSG_ERROR ("Adding Rule (1) to Filtering block Failed.");
+		bRetVal = false;
+		goto bail;
+	} else
+	{
+		LOG_MSG_DEBUG("flt rule hdl1=0x%x, status=0x%x\n", cFilterTable0.ReadRuleFromTable(1)->flt_rule_hdl,cFilterTable0.ReadRuleFromTable(1)->status);
+	}
+
+bail:
+	Free(pHeaderDescriptor);
+	LOG_MSG_STACK(
+		"Leaving Function (Returning %s)", bRetVal?"True":"False");
+	return bRetVal;
+} // AddRulesAggDualFcRoutingBased()
+

+ 113 - 0
kernel-tests/RNDISAggregationTestFixture.h

@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <linux/if_ether.h>
+
+#include "Constants.h"
+#include "Logger.h"
+#include "linux/msm_ipa.h"
+#include "TestsUtils.h"
+#include "TestBase.h"
+#include "Pipe.h"
+#include "RoutingDriverWrapper.h"
+#include "HeaderInsertion.h"
+#include "Filtering.h"
+#include "IPAFilteringTable.h"
+#define MAX_PACKET_SIZE 1024
+
+/*This class will be the base class of RNDIS Aggregation tests.
+ *Any method other than the test case itself can be
+ *declared in this Fixture thus allowing the derived classes to
+ *implement only the test case.
+ *All the test of the Aggregation uses one input and one output in DMA mode.
+ */
+class RNDISAggregationTestFixture:public TestBase
+{
+public:
+	/*This Constructor will register each instance that it creates.*/
+	RNDISAggregationTestFixture();
+
+	/*This method will create and initialize two Pipe object for the USB
+	 *(Ethernet) Pipes, one as input and the other as output.
+	 */
+	virtual bool Setup();
+
+	/*This method will destroy the pipes.*/
+	virtual bool Teardown();
+
+	virtual bool Run();
+
+	virtual bool AddRules() = 0;
+
+	virtual bool TestLogic() = 0;
+
+	bool AddRulesNoAgg();
+
+	bool AddRulesDeAggEther();
+
+	bool AddRulesAggTimeLimit();
+
+	bool AddRulesAggByteLimit();
+
+	bool AddRulesAggByteLimit(bool bAggForceClose);
+
+	bool AddRulesAggPacketLimit();
+
+	bool AddRulesAggDualFC();
+
+	bool AddRulesAggDualFcRoutingBased();
+
+	/*The client type are set from the peripheral perspective*/
+	static Pipe m_IpaToUsbPipeAgg;
+	/*IPA_CLIENT_TEST2_CONS (pipe_num = 7)*/
+	static Pipe m_UsbToIpaPipe;
+	/* IPA_CLIENT_TEST_PROD (pipe_num = 11)*/
+	static Pipe m_IpaToUsbPipe;
+	/* IPA_CLIENT_TEST3_CONS (pipe_num = 9)*/
+	static Pipe m_UsbToIpaPipeDeagg;
+	/* IPA_CLIENT_TEST2_PROD (pipe_num = 6)*/
+	static Pipe m_IpaToUsbPipeAggTime;
+	/* IPA_CLIENT_TEST_CONS (pipe_num = 10)*/
+	static Pipe m_IpaToUsbPipeAggPktLimit;
+	/* IPA_CLIENT_TEST4_CONS (pipe_num = 4)*/
+	static Pipe m_HsicToIpaPipe;
+	/* IPA_CLIENT_TEST3_PROD (pipe_num = 13)*/
+
+	static RoutingDriverWrapper m_Routing;
+	static Filtering m_Filtering;
+	static HeaderInsertion m_HeaderInsertion;
+
+protected:
+	enum ipa_ip_type m_eIP;
+};

+ 1265 - 0
kernel-tests/RNDISAggregationTests.cpp

@@ -0,0 +1,1265 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include "hton.h" /* for htonl*/
+#include "RNDISAggregationTestFixture.h"
+#include "Constants.h"
+#include "TestsUtils.h"
+#include "linux/msm_ipa.h"
+
+#define IPV4_DST_ADDR_OFFSET (16)
+#define IPV4_DST_ADDR_OFFSET_IN_ETH \
+		(16 /* IP */ + 14 /* ethernet */)
+#define IPV4_DST_ADDR_OFFSET_IN_RNDIS \
+		(IPV4_DST_ADDR_OFFSET_IN_ETH + \
+				sizeof(struct RndisHeader))
+
+#define NUM_PACKETS (4)
+
+class RNDISAggregationSanityTest: public RNDISAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	RNDISAggregationSanityTest()
+	{
+		m_name = "RNDISAggregationSanityTest";
+		m_description = "RNDISAggregationSanityTest - Send one packet "
+			"and expect same packet.";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRulesNoAgg();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		//The packets that will be sent
+		Byte pPacket[MAX_PACKET_SIZE];
+		//Buffer for the packet that will be received
+		Byte pReceivedPacket[2*MAX_PACKET_SIZE];
+		//Total size of all sent packets (this is the max size of the aggregated
+		//packet minus the size of the header and the NDP)
+		//int nTotalPacketsSize = MAX_PACKET_SIZE - (4 * NUM_PACKETS) - 24;
+		uint32_t nIPv4DSTAddr;
+		size_t pIpPacketsSize;
+
+		//initialize the packets
+		// Load input data (Ethernet packet) from file
+		pIpPacketsSize = MAX_PACKET_SIZE;
+		if (!RNDISAggregationHelper::LoadEtherPacket(m_eIP, pPacket, pIpPacketsSize))
+		{
+			LOG_MSG_ERROR("Failed default Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pPacket[IPV4_DST_ADDR_OFFSET_IN_ETH],&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+
+
+		//send the packet
+		LOG_MSG_DEBUG("Sending packet into the A2 EMB pipe(%d bytes)\n",
+				pIpPacketsSize);
+		size_t nBytesSent = m_UsbToIpaPipe.Send(pPacket, pIpPacketsSize);
+		if (pIpPacketsSize != nBytesSent)
+		{
+			LOG_MSG_ERROR("Sending packet into the A2 EMB pipe(%d bytes) "
+				"failed!\n", pIpPacketsSize);
+			return false;
+		}
+
+		//receive the packet
+		LOG_MSG_DEBUG("Reading packet from the A2 EMB pipe(%d bytes should be there)"
+			"\n", pIpPacketsSize);
+		size_t nBytesReceived = m_IpaToUsbPipe.Receive(pReceivedPacket, MAX_PACKET_SIZE);
+		if (pIpPacketsSize != nBytesReceived)
+		{
+			LOG_MSG_ERROR("Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", pIpPacketsSize);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+		return RNDISAggregationHelper::ComparePackets(pReceivedPacket, nBytesReceived,
+			pPacket, pIpPacketsSize);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+class RNDISAggregationDeaggregation1PacketTest: public RNDISAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	RNDISAggregationDeaggregation1PacketTest()
+	{
+		m_name = "RNDISAggregationDeaggregation1PacketTest";
+		m_description = "RNDISAggregationDeaggregation1PacketTest - Send 1 RNDIS packet "
+			"and expect Ethernet packet.";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRulesDeAggEther();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		//The packets that will be sent
+		Byte pPacket[MAX_PACKET_SIZE];
+		//Buffer for the packet that will be received
+		Byte pReceivedPacket[2*MAX_PACKET_SIZE];
+		//Total size of all sent packets (this is the max size of the aggregated
+		//packet minus the size of the header and the NDP)
+		//int nTotalPacketsSize = MAX_PACKET_SIZE - (4 * NUM_PACKETS) - 24;
+		uint32_t nIPv4DSTAddr;
+		size_t pIpPacketsSize;
+
+		//initialize the packets
+		// Load input data (IP packet) from file
+		pIpPacketsSize = MAX_PACKET_SIZE;
+		if (!RNDISAggregationHelper::LoadRNDISPacket(m_eIP, pPacket, pIpPacketsSize))
+		{
+			LOG_MSG_ERROR("Failed to load RNDIS Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pPacket[IPV4_DST_ADDR_OFFSET_IN_RNDIS],&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+
+		//send the packet
+		LOG_MSG_DEBUG("Sending packet into the A2 TETH pipe(%d bytes)\n",
+				pIpPacketsSize);
+		size_t nBytesSent = m_UsbToIpaPipeDeagg.Send(pPacket, pIpPacketsSize);
+		if (pIpPacketsSize != nBytesSent)
+		{
+			LOG_MSG_ERROR("Sending packet into the A2 EMB pipe(%d bytes) "
+				"failed!\n", pIpPacketsSize);
+			return false;
+		}
+
+		//receive the packet
+		LOG_MSG_DEBUG("Reading packet from the A2 TETH pipe(%d bytes should be there)"
+			"\n", pIpPacketsSize);
+		size_t nBytesReceived = m_IpaToUsbPipe.Receive(pReceivedPacket, MAX_PACKET_SIZE);
+		if (pIpPacketsSize - sizeof(struct RndisHeader) != nBytesReceived)
+		{
+			LOG_MSG_ERROR("Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", pIpPacketsSize);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+		return RNDISAggregationHelper::CompareEthervsRNDISPacket(pReceivedPacket, nBytesReceived,
+			pPacket, pIpPacketsSize);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+class RNDISAggregation1PacketTest: public RNDISAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	RNDISAggregation1PacketTest()
+	{
+		m_name = "RNDISAggregation1PacketTest";
+		m_description = "RNDISAggregation1PacketTest - Send 1 IP packet "
+			"and expect RNDIS packet.";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRulesAggTimeLimit();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		//The packets that will be sent
+		Byte pPacket[MAX_PACKET_SIZE];
+		//Buffer for the packet that will be received
+		Byte pReceivedPacket[2*MAX_PACKET_SIZE];
+		//Total size of all sent packets (this is the max size of the aggregated
+		//packet minus the size of the header and the NDP)
+		//int nTotalPacketsSize = MAX_PACKET_SIZE - (4 * NUM_PACKETS) - 24;
+		uint32_t nIPv4DSTAddr;
+		size_t pIpPacketsSize;
+
+		//initialize the packets
+		// Load input data (IP packet) from file
+		pIpPacketsSize = MAX_PACKET_SIZE;
+		if (!LoadDefaultPacket(m_eIP, pPacket, pIpPacketsSize))
+		{
+			LOG_MSG_ERROR("Failed to load Ethernet Packet");
+			return false;
+		}
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&pPacket[IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+
+		//send the packet
+		LOG_MSG_DEBUG("Sending packet into the USB pipe(%d bytes)\n",
+				pIpPacketsSize);
+		size_t nBytesSent = m_HsicToIpaPipe.Send(pPacket, pIpPacketsSize);
+		if (pIpPacketsSize != nBytesSent)
+		{
+			LOG_MSG_ERROR("Sending packet into the USB pipe(%d bytes) "
+				"failed!\n", pIpPacketsSize);
+			return false;
+		}
+
+		//receive the packet
+		LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be there)"
+			"\n", pIpPacketsSize);
+		size_t nBytesReceived = m_IpaToUsbPipeAggTime.Receive(pReceivedPacket, MAX_PACKET_SIZE);
+		if (pIpPacketsSize != nBytesReceived - sizeof(struct RndisEtherHeader))
+		{
+			LOG_MSG_ERROR("Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", pIpPacketsSize);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+
+
+		return RNDISAggregationHelper::CompareIPvsRNDISPacket(pPacket, pIpPacketsSize,
+			pReceivedPacket, nBytesReceived);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+class RNDISAggregationSuspendWaTest: public RNDISAggregationTestFixture {
+public:
+	/////////////////////////////////////////////////////////////////////////////////
+
+	RNDISAggregationSuspendWaTest()
+	{
+		m_name = "RNDISAggregationSuspendWaTest";
+		m_description = "RNDISAggregationSuspendWaTest - Send 3 IP packet instead 4, suspend the pipe"
+			" and expect aggregation to be closed.";
+		m_minIPAHwType = IPA_HW_v3_0;
+
+		// WA not needed in IPA_3_5
+		m_maxIPAHwType = IPA_HW_v3_1;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRulesAggByteLimit();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool Setup()
+	{
+		bool bRetVal = true;
+
+		bRetVal = RNDISAggregationTestFixture::Setup();
+		if (bRetVal == false) {
+			return bRetVal;
+		}
+
+		/* register test framework suspend handler to from_ipa_devs */
+		bRetVal = RegSuspendHandler(false, true, 0);
+
+		return bRetVal;
+	}
+
+	bool TestLogic()
+	{
+		/*The packets that will be sent*/
+
+		Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+		/*Buffer for the packet that will be received*/
+		Byte pReceivedPacket[2*MAX_PACKET_SIZE];
+		/*
+		 *Total size of all sent packets
+		 * (this is the max size of the aggregated
+		 *packet minus the size of the header and the NDP)
+		 */
+		uint32_t nIPv4DSTAddr;
+		size_t pIpPacketsSizes[NUM_PACKETS];
+		size_t ExpectedPacketSize = (NUM_PACKETS - 1) * sizeof(struct RndisEtherHeader);
+
+		struct ipa_test_ep_ctrl ep_ctrl;
+
+		/* send one packet less than aggregation size in order to see the force close */
+		for(int i = 0; i < (NUM_PACKETS - 1); i++) {
+			/*
+			 *initialize the packets
+			 *Load input data (IP packet) from file
+			 */
+			pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+			if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+			{
+				LOG_MSG_ERROR("Failed to load Ethernet Packet");
+				return false;
+			}
+			nIPv4DSTAddr = ntohl(0x7F000001);
+			memcpy (&pPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+			for(int j = pIpPacketsSizes[i]; j < MAX_PACKET_SIZE / NUM_PACKETS + 1; j++) {
+				pPackets[i][j] = j & 0xFF;
+			}
+			pIpPacketsSizes[i] = MAX_PACKET_SIZE / NUM_PACKETS + 1;
+
+			/* send the packet */
+			LOG_MSG_DEBUG("Sending packet into the A2 TETH pipe(%d bytes)\n",
+					pIpPacketsSizes[i]);
+			size_t nBytesSent = m_HsicToIpaPipe.Send(pPackets[i], pIpPacketsSizes[i]);
+			if (pIpPacketsSizes[i] != nBytesSent)
+			{
+				LOG_MSG_ERROR("Sending packet into the USB pipe(%d bytes) "
+					"failed!\n", pIpPacketsSizes[i]);
+				return false;
+			}
+			ExpectedPacketSize += pIpPacketsSizes[i];
+		}
+
+		/* suspend the pipe */
+		ep_ctrl.from_dev_num = 0;
+		ep_ctrl.ipa_ep_delay = false;
+		ep_ctrl.ipa_ep_suspend = true;
+		configure_ep_ctrl(&ep_ctrl);
+
+		/* receive the packet */
+		LOG_MSG_DEBUG(
+			"Reading packet from the USB pipe(%d bytes should be there)"
+			"\n", ExpectedPacketSize);
+		size_t nBytesReceived = m_IpaToUsbPipeAgg
+				.Receive(pReceivedPacket, MAX_PACKET_SIZE);
+		if (ExpectedPacketSize != nBytesReceived)
+		{
+			LOG_MSG_ERROR(
+				"Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", nBytesReceived);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+
+
+		for(int i = 0; i < (NUM_PACKETS - 1); i++) {
+			if (!RNDISAggregationHelper::
+					CompareIPvsRNDISPacket(pPackets[i], pIpPacketsSizes[i],
+				pReceivedPacket + (i * ExpectedPacketSize / (NUM_PACKETS - 1)),
+				ExpectedPacketSize / (NUM_PACKETS - 1)))
+				return false;
+		}
+
+		return true;
+	}
+
+	bool Teardown()
+	{
+		bool bRetVal = true;
+
+		bRetVal = RNDISAggregationTestFixture::Teardown();
+		if (bRetVal == false) {
+			return bRetVal;
+		}
+
+		/* unregister the test framework suspend handler */
+		bRetVal = RegSuspendHandler(false, false, 0);
+
+		return bRetVal;
+	}
+};
+
+class RNDISAggregationByteLimitTest: public RNDISAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	RNDISAggregationByteLimitTest()
+	{
+		m_name = "RNDISAggregationByteLimitTest";
+		m_description = "RNDISAggregationByteLimitTest - Send 2 IP packet "
+			"and expect aggregated RNDIS packet.";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRulesAggByteLimit();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		/*The packets that will be sent*/
+
+		Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+		/*Buffer for the packet that will be received*/
+		Byte pReceivedPacket[2*MAX_PACKET_SIZE];
+		/*Total size of all sent packets
+		 * (this is the max size of the aggregated
+		 *packet minus the size of the header and the NDP)
+		 */
+		uint32_t nIPv4DSTAddr;
+		size_t pIpPacketsSizes[NUM_PACKETS];
+		size_t ExpectedPacketSize = NUM_PACKETS * sizeof(struct RndisEtherHeader);
+
+		for(int i = 0; i < NUM_PACKETS; i++) {
+			/*
+			 *initialize the packets
+			 *Load input data (IP packet) from file
+			 */
+			pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+			if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+			{
+				LOG_MSG_ERROR("Failed to load Ethernet Packet");
+				return false;
+			}
+			nIPv4DSTAddr = ntohl(0x7F000001);
+			memcpy (&pPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+			for(int j = pIpPacketsSizes[i]; j < MAX_PACKET_SIZE / NUM_PACKETS + 1; j++) {
+				pPackets[i][j] = j & 0xFF;
+			}
+			pIpPacketsSizes[i] = MAX_PACKET_SIZE / NUM_PACKETS + 1;
+
+			/* send the packet */
+			LOG_MSG_DEBUG("Sending packet into the A2 TETH pipe(%d bytes)\n",
+					pIpPacketsSizes[i]);
+			size_t nBytesSent = m_HsicToIpaPipe.Send(pPackets[i], pIpPacketsSizes[i]);
+			if (pIpPacketsSizes[i] != nBytesSent)
+			{
+				LOG_MSG_ERROR("Sending packet into the USB pipe(%d bytes) "
+					"failed!\n", pIpPacketsSizes[i]);
+				return false;
+			}
+			ExpectedPacketSize += pIpPacketsSizes[i];
+		}
+
+		/* receive the packet */
+		LOG_MSG_DEBUG(
+			"Reading packet from the USB pipe(%d bytes should be there)"
+			"\n", ExpectedPacketSize);
+		size_t nBytesReceived = m_IpaToUsbPipeAgg
+				.Receive(pReceivedPacket, MAX_PACKET_SIZE);
+		if (ExpectedPacketSize != nBytesReceived)
+		{
+			LOG_MSG_ERROR(
+				"Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", nBytesReceived);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+
+
+		for(int i = 0; i < NUM_PACKETS; i++) {
+			if (!RNDISAggregationHelper::
+					CompareIPvsRNDISPacket(pPackets[i], pIpPacketsSizes[i],
+				pReceivedPacket + (i * ExpectedPacketSize / NUM_PACKETS),
+				ExpectedPacketSize / NUM_PACKETS))
+				return false;
+		}
+
+		return true;
+	}
+};
+
+class RNDISAggregationByteLimitTestFC : public RNDISAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	RNDISAggregationByteLimitTestFC() {
+		m_name = "RNDISAggregationByteLimitTestFC";
+		m_description = "RNDISAggregationByteLimitTestFC - Send 4 IP packet with FC"
+			"and expect 4 aggregated RNDIS packets.";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules() {
+		return AddRulesAggByteLimit(true);
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic() {
+		/*The packets that will be sent*/
+
+		Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+		/*Buffer for the packets that will be received*/
+		Byte pReceivedPacket[NUM_PACKETS][MAX_PACKET_SIZE];
+		/*Total size of all sent packets
+		 * (this is the max size of the aggregated
+		 *packet minus the size of the header and the NDP)
+		 */
+		uint32_t nIPv4DSTAddr;
+		size_t pIpPacketsSizes[NUM_PACKETS];
+		size_t ExpectedPacketSize =
+			sizeof(struct RndisEtherHeader) + MAX_PACKET_SIZE / NUM_PACKETS + 1;
+
+		for (int i = 0; i < NUM_PACKETS; i++) {
+			/*
+			 *initialize the packets
+			 *Load input data (IP packet) from file
+			 */
+			pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+			if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i])) {
+				LOG_MSG_ERROR("Failed to load Ethernet Packet");
+				return false;
+			}
+			nIPv4DSTAddr = ntohl(0x7F000001);
+			memcpy(&pPackets[i][IPV4_DST_ADDR_OFFSET], &nIPv4DSTAddr,
+				   sizeof(nIPv4DSTAddr));
+			for (int j = pIpPacketsSizes[i]; j < MAX_PACKET_SIZE / NUM_PACKETS + 1; j++) {
+				pPackets[i][j] = j & 0xFF;
+			}
+			pIpPacketsSizes[i] = MAX_PACKET_SIZE / NUM_PACKETS + 1;
+
+			/* send the packet */
+			LOG_MSG_DEBUG("Sending packet into the A2 TETH pipe(%d bytes)\n",
+						  pIpPacketsSizes[i]);
+			size_t nBytesSent = m_HsicToIpaPipe.Send(pPackets[i], pIpPacketsSizes[i]);
+			if (pIpPacketsSizes[i] != nBytesSent) {
+				LOG_MSG_ERROR("Sending packet into the USB pipe(%d bytes) "
+							  "failed!\n", pIpPacketsSizes[i]);
+				return false;
+			}
+		}
+
+		/* receive the packet */
+		LOG_MSG_DEBUG(
+			"Reading packets from the USB pipe(%d bytes for each)"
+			"\n", ExpectedPacketSize);
+		for (int i = 0; i < NUM_PACKETS; i++) {
+			size_t nBytesReceived = m_IpaToUsbPipeAgg
+				.Receive(pReceivedPacket[i], MAX_PACKET_SIZE);
+			if (ExpectedPacketSize != nBytesReceived) {
+				LOG_MSG_ERROR(
+					"Receiving aggregated packet from the USB pipe(%d bytes) "
+					"failed!\n", nBytesReceived);
+				print_buff(pReceivedPacket[i], nBytesReceived);
+				return false;
+			}
+			print_buff(pReceivedPacket, nBytesReceived);
+		}
+
+
+		for (int i = 0; i < NUM_PACKETS; i++) {
+			if (!RNDISAggregationHelper::CompareIPvsRNDISPacket(
+					pPackets[i],
+					pIpPacketsSizes[i],
+					pReceivedPacket[i],
+					ExpectedPacketSize)) return false;
+		}
+
+		return true;
+	}
+};
+
+class RNDISAggregationDualDpTestFC : public RNDISAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	RNDISAggregationDualDpTestFC() {
+		m_name = "RNDISAggregationDualDpTestFC";
+		m_description = "RNDISAggregationDualDpTestFC - Send IP packets "
+			"on two datapathes: one with FC and one without. "
+			"Expect 2 aggregated RNDIS packets on pipe with FC. "
+			"Expect one aggregated RNDIS packet on pipe without FC. ";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules() {
+		return AddRulesAggDualFC();
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic() {
+		int i;
+		/* The packets that will be sent */
+		Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+		/* Buffer for the packets that will be received */
+		Byte pReceivedPacket[(NUM_PACKETS / 2) * MAX_PACKET_SIZE];
+		Byte pReceivedPacketFC[NUM_PACKETS / 2][MAX_PACKET_SIZE];
+		/*
+		 * Total size of all sent packets
+		 * (this is the max size of the aggregated
+		 * packet minus the size of the header and the NDP)
+		 */
+		uint32_t nIPv4DSTAddr;
+		size_t nBytesReceived;
+		size_t pIpPacketsSizes[NUM_PACKETS];
+		size_t ExpectedPacketSize =
+			sizeof(struct RndisEtherHeader) + MAX_PACKET_SIZE / NUM_PACKETS + 1;
+
+		for (i = 0; i < NUM_PACKETS; i++) {
+			/*
+			 * Initialize the packets
+			 * Load input data (IP packet) from file
+			 */
+			pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+			if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i])) {
+				LOG_MSG_ERROR("Failed to load Ethernet Packet");
+				return false;
+			}
+			/*
+			 * Half of the packets will go to 127.0.0.1
+			 * and the other half to 127.0.0.2
+			 */
+			nIPv4DSTAddr = ntohl(0x7F000001 + (i & 0x1));
+			memcpy(&pPackets[i][IPV4_DST_ADDR_OFFSET], &nIPv4DSTAddr,
+				   sizeof(nIPv4DSTAddr));
+			for (int j = pIpPacketsSizes[i]; j < MAX_PACKET_SIZE / NUM_PACKETS + 1; j++) {
+				pPackets[i][j] = j & 0xFF;
+			}
+			pIpPacketsSizes[i] = MAX_PACKET_SIZE / NUM_PACKETS + 1;
+
+			/* send the packet */
+			LOG_MSG_DEBUG("Sending packet into the m_HsicToIpaPipe pipe (%d bytes)\n",
+						  pIpPacketsSizes[i]);
+			print_buff(pPackets[i], pIpPacketsSizes[i]);
+			size_t nBytesSent = m_HsicToIpaPipe.Send(pPackets[i], pIpPacketsSizes[i]);
+			if (pIpPacketsSizes[i] != nBytesSent) {
+				LOG_MSG_ERROR("Sending packet into the m_HsicToIpaPipe pipe (%d bytes) "
+							  "failed!\n", pIpPacketsSizes[i]);
+				return false;
+			}
+		}
+
+		/* receive the packets from FC pipe */
+		LOG_MSG_DEBUG(
+			"Reading packets from the m_IpaToUsbPipeAgg pipe (%d bytes for each)"
+			"\n", ExpectedPacketSize);
+		for (i = 0; i < NUM_PACKETS / 2; i++) {
+			nBytesReceived = m_IpaToUsbPipeAgg
+				.Receive(pReceivedPacketFC[i], MAX_PACKET_SIZE);
+			if (ExpectedPacketSize != nBytesReceived) {
+				LOG_MSG_ERROR(
+					"Receiving aggregated packet from the m_IpaToUsbPipeAgg pipe (%d bytes) "
+					"failed!\n", nBytesReceived);
+				print_buff(pReceivedPacketFC[i], nBytesReceived);
+				return false;
+			}
+		}
+
+		for (i = 0; i < NUM_PACKETS / 2; i++) {
+			if (!RNDISAggregationHelper::CompareIPvsRNDISPacket(
+					pPackets[i * 2],
+					pIpPacketsSizes[i * 2],
+					pReceivedPacketFC[i],
+					ExpectedPacketSize)) return false;
+		}
+
+		/* receive the packet from non-FC pipe */
+		LOG_MSG_DEBUG(
+			"Reading packet from the m_IpaToUsbPipeAggPktLimit pipe (%d bytes)"
+			"\n", ExpectedPacketSize * 2);
+		nBytesReceived = m_IpaToUsbPipeAggPktLimit
+			.Receive(pReceivedPacket, MAX_PACKET_SIZE);
+		if (ExpectedPacketSize * 2 != nBytesReceived) {
+			LOG_MSG_ERROR(
+				"Receiving aggregated packets from the m_IpaToUsbPipeAggPktLimit pipe (%d bytes) "
+				"failed!\n", nBytesReceived);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+
+		for (int i = 0; i < NUM_PACKETS; i += 2) {
+			if (!RNDISAggregationHelper::CompareIPvsRNDISPacket(
+					pPackets[i + 1], // Odd packets are in the second pipe
+					pIpPacketsSizes[i + 1],
+					pReceivedPacket + (i * ExpectedPacketSize / 2),
+					ExpectedPacketSize))
+				return false;
+		}
+
+		return true;
+	}
+};
+
+class RNDISAggregationDualDpTestFcRoutingBased : public RNDISAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	RNDISAggregationDualDpTestFcRoutingBased() {
+		m_name = "RNDISAggregationDualDpTestFcRoutingBased";
+		m_description = "RNDISAggregationDualDpTestFcRoutingBased - Send IP packets "
+			"on two datapathes: one with RT based FC and one without. "
+			"Expect 2 aggregated RNDIS packets on pipe with RT based FC. "
+			"Expect one aggregated RNDIS packet on pipe without RT based FC. ";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules() {
+		return AddRulesAggDualFcRoutingBased();
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic() {
+		int i;
+		/* The packets that will be sent */
+		Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+		/* Buffer for the packets that will be received */
+		Byte pReceivedPacket[(NUM_PACKETS / 2) * MAX_PACKET_SIZE];
+		Byte pReceivedPacketFC[NUM_PACKETS / 2][MAX_PACKET_SIZE];
+		/*
+		 * Total size of all sent packets
+		 * (this is the max size of the aggregated
+		 * packet minus the size of the header and the NDP)
+		 */
+		uint32_t nIPv4DSTAddr;
+		size_t nBytesReceived;
+		size_t pIpPacketsSizes[NUM_PACKETS];
+		size_t ExpectedPacketSize =
+			sizeof(struct RndisEtherHeader) + MAX_PACKET_SIZE / NUM_PACKETS + 1;
+
+		for (i = 0; i < NUM_PACKETS; i++) {
+			/*
+			 * Initialize the packets
+			 * Load input data (IP packet) from file
+			 */
+			pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+			if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i])) {
+				LOG_MSG_ERROR("Failed to load Ethernet Packet");
+				return false;
+			}
+			/*
+			 * Half of the packets will go to 127.0.0.1
+			 * and the other half to 127.0.0.2
+			 */
+			nIPv4DSTAddr = ntohl(0x7F000001 + (i & 0x1));
+			memcpy(&pPackets[i][IPV4_DST_ADDR_OFFSET], &nIPv4DSTAddr,
+				   sizeof(nIPv4DSTAddr));
+			for (int j = pIpPacketsSizes[i]; j < MAX_PACKET_SIZE / NUM_PACKETS + 1; j++) {
+				pPackets[i][j] = j & 0xFF;
+			}
+			pIpPacketsSizes[i] = MAX_PACKET_SIZE / NUM_PACKETS + 1;
+
+			/* send the packet */
+			LOG_MSG_DEBUG("Sending packet into the m_HsicToIpaPipe pipe (%d bytes)\n",
+						  pIpPacketsSizes[i]);
+			print_buff(pPackets[i], pIpPacketsSizes[i]);
+			size_t nBytesSent = m_HsicToIpaPipe.Send(pPackets[i], pIpPacketsSizes[i]);
+			if (pIpPacketsSizes[i] != nBytesSent) {
+				LOG_MSG_ERROR("Sending packet into the m_HsicToIpaPipe pipe (%d bytes) "
+							  "failed!\n", pIpPacketsSizes[i]);
+				return false;
+			}
+		}
+
+		/* receive the packets from FC pipe */
+		LOG_MSG_DEBUG(
+			"Reading packets from the m_IpaToUsbPipeAgg pipe (%d bytes for each)"
+			"\n", ExpectedPacketSize);
+		for (i = 0; i < NUM_PACKETS / 2; i++) {
+			nBytesReceived = m_IpaToUsbPipeAgg
+				.Receive(pReceivedPacketFC[i], MAX_PACKET_SIZE);
+			if (ExpectedPacketSize != nBytesReceived) {
+				LOG_MSG_ERROR(
+					"Receiving aggregated packet from the m_IpaToUsbPipeAgg pipe (%d bytes) "
+					"failed!\n", nBytesReceived);
+				print_buff(pReceivedPacketFC[i], nBytesReceived);
+				return false;
+			}
+		}
+
+		for (i = 0; i < NUM_PACKETS / 2; i++) {
+			if (!RNDISAggregationHelper::CompareIPvsRNDISPacket(
+					pPackets[i * 2],
+					pIpPacketsSizes[i * 2],
+					pReceivedPacketFC[i],
+					ExpectedPacketSize)) return false;
+		}
+
+		/* receive the packet from non-FC pipe */
+		LOG_MSG_DEBUG(
+			"Reading packet from the m_IpaToUsbPipeAggPktLimit pipe (%d bytes)"
+			"\n", ExpectedPacketSize * 2);
+		nBytesReceived = m_IpaToUsbPipeAggPktLimit
+			.Receive(pReceivedPacket, MAX_PACKET_SIZE);
+		if (ExpectedPacketSize * 2 != nBytesReceived) {
+			LOG_MSG_ERROR(
+				"Receiving aggregated packets from the m_IpaToUsbPipeAggPktLimit pipe (%d bytes) "
+				"failed!\n", nBytesReceived);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+
+		for (int i = 0; i < NUM_PACKETS; i += 2) {
+			if (!RNDISAggregationHelper::CompareIPvsRNDISPacket(
+					pPackets[i + 1], // Odd packets are in the second pipe
+					pIpPacketsSizes[i + 1],
+					pReceivedPacket + (i * ExpectedPacketSize / 2),
+					ExpectedPacketSize))
+				return false;
+		}
+
+		return true;
+	}
+};
+
+class RNDISAggregationDeaggregationNumPacketsTest:
+	public RNDISAggregationTestFixture {
+public:
+
+	RNDISAggregationDeaggregationNumPacketsTest()
+	{
+		m_name = "RNDISAggregationDeaggregationNumPacketsTest";
+		m_description = "RNDISAggregationByteLimitTest - Send on IP packet "
+			"and expect aggregated RNDIS packet.";
+	}
+
+	virtual bool AddRules()
+	{
+		return AddRulesDeAggEther();
+	} /* AddRules()*/
+
+	bool TestLogic()
+	{
+		/*the packets that will be sent*/
+		Byte pPacket[MAX_PACKET_SIZE];
+		//Buffer for the packet that will be received
+		Byte pReceivedPacket[2*MAX_PACKET_SIZE];
+		//Total size of all sent packets (this is the max size of the aggregated
+		//packet minus the size of the header and the NDP)
+		uint32_t nIPv4DSTAddr;
+		size_t pIpPacketsSize;
+		size_t pAggrPacketsSize = 0;
+
+		for(int i = 0; i < NUM_PACKETS; i++) {
+			//initialize the packets
+			// Load input data (RNDIS packet) from file
+			pIpPacketsSize = MAX_PACKET_SIZE;
+			if (!RNDISAggregationHelper::LoadRNDISPacket(m_eIP, pPacket + pAggrPacketsSize, pIpPacketsSize))
+			{
+				LOG_MSG_ERROR("Failed to load Ethernet Packet");
+				return false;
+			}
+			pAggrPacketsSize += pIpPacketsSize;
+			nIPv4DSTAddr = ntohl(0x7F000001);
+			memcpy (&((pPacket + i * pIpPacketsSize)[IPV4_DST_ADDR_OFFSET_IN_RNDIS]),&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		}
+		print_buff(pPacket, pAggrPacketsSize);
+
+		/*send the packet*/
+		LOG_MSG_DEBUG("Sending packet into the A2 TETH pipe(%d bytes)\n",
+					pIpPacketsSize * NUM_PACKETS);
+		size_t nBytesSent = m_UsbToIpaPipeDeagg.Send(pPacket, pAggrPacketsSize);
+		if (pAggrPacketsSize != nBytesSent)
+		{
+			LOG_MSG_ERROR("Sending packet into the USB pipe(%d bytes) "
+				"failed!\n", pIpPacketsSize * NUM_PACKETS);
+			return false;
+		}
+		for(int i = 0; i < NUM_PACKETS; i++) {
+			//receive the packet, one by one
+			LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be there)"
+				"\n", pIpPacketsSize - sizeof(struct RndisHeader));
+			size_t nBytesReceived = m_IpaToUsbPipe.Receive(pReceivedPacket, MAX_PACKET_SIZE);
+			if (pIpPacketsSize - sizeof(struct RndisHeader) != nBytesReceived)
+			{
+				LOG_MSG_ERROR("Receiving aggregated packet from the USB pipe(%d bytes) "
+					"failed!\n", nBytesReceived);
+				print_buff(pReceivedPacket, nBytesReceived);
+				return false;
+			}
+			if (!RNDISAggregationHelper::CompareEthervsRNDISPacket(pReceivedPacket,
+										nBytesReceived,
+										pPacket + i * pIpPacketsSize,
+									       pIpPacketsSize))
+				return false;
+		}
+
+		return true;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+class RNDISAggregationDeaggregationExceptionPacketsTest:
+	public RNDISAggregationTestFixture {
+public:
+
+	RNDISAggregationDeaggregationExceptionPacketsTest()
+	{
+		m_name = "RNDISAggregationDeaggregationExceptionPacketsTest";
+		m_description = "RNDISAggregationDeaggregationExceptionPacketsTest - Send 5 frames "
+			"of size 43 bytes, 1025 bytes, 43 bytes, 981 bytes, and 1024 bytes "
+			"and expect aggregated RNDIS packet.";
+	}
+
+	virtual bool AddRules()
+	{
+		return AddRulesDeAggEther();
+	} /* AddRules()*/
+
+	bool TestLogic()
+	{
+		/*the packets that will be sent*/
+		Byte pPacket[MAX_PACKET_SIZE];
+		Byte pPacket1[MAX_PACKET_SIZE +1];
+		Byte pPacket2[MAX_PACKET_SIZE];
+		Byte pPacket3[MAX_PACKET_SIZE];
+
+		//Buffer for the packet that will be received
+		Byte pReceivedPacket[2*MAX_PACKET_SIZE];
+		//Total size of all sent packets (this is the max size of the aggregated
+		//packet minus the size of the header and the NDP)
+		uint32_t nIPv4DSTAddr;
+		size_t pIpPacketsSize;
+		size_t pAggrPacketsSize = 0;
+		size_t nBytesSent;
+		size_t nBytesReceived;
+
+		/* Create the frame of size 43 bytes which is one less byte than RNDIS header */
+		pAggrPacketsSize  = sizeof(struct RndisHeader) - 1;
+		struct RndisHeader *pRndisHeader = (struct RndisHeader*)pPacket;
+		memset(pRndisHeader, 0, (sizeof(struct RndisHeader) - 1));
+		pRndisHeader->MessageType = 0x01;
+		pRndisHeader->MessageLength = pAggrPacketsSize;
+		pRndisHeader->DataOffset = 0x24;
+		pRndisHeader->DataLength = 0;
+
+		nIPv4DSTAddr = ntohl(0x7F000001);
+		memcpy (&((pPacket)[IPV4_DST_ADDR_OFFSET_IN_RNDIS]),&nIPv4DSTAddr,
+			sizeof(nIPv4DSTAddr));
+		print_buff(pPacket, pAggrPacketsSize);
+
+		/* Send the first frame */
+		LOG_MSG_DEBUG("Sending packet into the A2 TETH pipe(%d bytes)\n",
+					pAggrPacketsSize);
+		nBytesSent = m_UsbToIpaPipeDeagg.Send(pPacket, pAggrPacketsSize);
+		if (pAggrPacketsSize != nBytesSent)
+		{
+			LOG_MSG_ERROR("Sending packet into the USB pipe(%d bytes) "
+					"failed!\n", pAggrPacketsSize);
+			return false;
+		}
+		/* This is deaggregation exception packet, this packet should not arrive at this pipe */
+		LOG_MSG_DEBUG("Reading packet from the USB pipe(0 bytes should be there)\n");
+		nBytesReceived = m_IpaToUsbPipe.Receive(pReceivedPacket, MAX_PACKET_SIZE);
+		if (0 != nBytesReceived)
+		{
+			LOG_MSG_ERROR("Receiving aggregated packet from the USB pipe(%d bytes) "
+					"failed!\n", nBytesReceived);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+
+		/* Create a frame of size 1025 bytes */
+		pAggrPacketsSize = 0;
+		for(int i = 0; i < 8; i++) {
+			//initialize the packets
+			// Load input data (RNDIS packet) from file
+			pIpPacketsSize = MAX_PACKET_SIZE;
+			if (!RNDISAggregationHelper::LoadRNDISPacket(m_eIP, pPacket1 + pAggrPacketsSize, pIpPacketsSize))
+			{
+				LOG_MSG_ERROR("Failed to load Ethernet Packet");
+				return false;
+			}
+			pAggrPacketsSize += pIpPacketsSize;
+			nIPv4DSTAddr = ntohl(0x7F000001);
+			memcpy (&((pPacket1 + i * pIpPacketsSize)[IPV4_DST_ADDR_OFFSET_IN_RNDIS]),&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		}
+
+		pPacket1[pAggrPacketsSize] = 0xdd;
+		pAggrPacketsSize = pAggrPacketsSize + 1;
+
+                print_buff(pPacket1, pAggrPacketsSize);
+
+                /* Send the 2nd frame */
+		LOG_MSG_DEBUG("Sending packet into the A2 TETH pipe(%d bytes)\n",
+							pAggrPacketsSize);
+		nBytesSent = m_UsbToIpaPipeDeagg.Send(pPacket1, pAggrPacketsSize);
+		if (pAggrPacketsSize  != nBytesSent)
+		{
+			LOG_MSG_ERROR("Sending packet into the USB pipe(%d bytes) "
+					"failed!\n", pAggrPacketsSize);
+			return false;
+		}
+
+		for(int i = 0; i < 8; i++) {
+			//Receive the packet, one by one
+			LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be there)"
+				"\n", pIpPacketsSize - sizeof(struct RndisHeader));
+			size_t nBytesReceived = m_IpaToUsbPipe.Receive(pReceivedPacket, MAX_PACKET_SIZE);
+			if (pIpPacketsSize - sizeof(struct RndisHeader) != nBytesReceived)
+			{
+				LOG_MSG_ERROR("Receiving aggregated packet from the USB pipe(%d bytes) "
+					"failed!\n", nBytesReceived);
+				print_buff(pReceivedPacket, nBytesReceived);
+				return false;
+			}
+			if (!RNDISAggregationHelper::CompareEthervsRNDISPacket(pReceivedPacket,
+										nBytesReceived,
+										pPacket1 + i * pIpPacketsSize,
+										pIpPacketsSize))
+				return false;
+		}
+
+		/* Create a frame of size 1024 bytes and send as 2 frames */
+		pAggrPacketsSize = 0;
+		for(int i = 0; i < 8; i++) {
+			//initialize the packets
+			// Load input data (RNDIS packet) from file
+			pIpPacketsSize = MAX_PACKET_SIZE;
+			if (!RNDISAggregationHelper::LoadRNDISPacket(m_eIP, pPacket2 + pAggrPacketsSize, pIpPacketsSize))
+			{
+				LOG_MSG_ERROR("Failed to load Ethernet Packet");
+				return false;
+			}
+			pAggrPacketsSize += pIpPacketsSize;
+			nIPv4DSTAddr = ntohl(0x7F000001);
+			memcpy (&((pPacket2 + i * pIpPacketsSize)[IPV4_DST_ADDR_OFFSET_IN_RNDIS]),&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+		}
+		print_buff(pPacket2, pAggrPacketsSize);
+
+		/* Send the 3rd frame */
+		LOG_MSG_DEBUG("Sending packet into the A2 TETH pipe(%d bytes)\n", 43);
+		nBytesSent = m_UsbToIpaPipeDeagg.Send(pPacket2, 43);
+		if (43 != nBytesSent)
+		{
+			LOG_MSG_ERROR("Sending packet into the USB pipe(%d bytes) "
+				"failed!\n", 43);
+
+			return false;
+		}
+		/* This is deaggregation exception packet, this packet should not arrive at this pipe */
+		LOG_MSG_DEBUG("Reading packet from the USB pipe(0 bytes should be there)\n");
+		nBytesReceived = m_IpaToUsbPipe.Receive(pReceivedPacket, MAX_PACKET_SIZE);
+		if (0 != nBytesReceived)
+		{
+			LOG_MSG_ERROR("Receiving aggregated packet from the USB pipe(%d bytes) "
+					"failed!\n", nBytesReceived);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+		/* Send the 4rd frame */
+		LOG_MSG_DEBUG("Sending packet into the A2 TETH pipe(%d bytes)\n",
+						pAggrPacketsSize - 43 );
+		nBytesSent = m_UsbToIpaPipeDeagg.Send((pPacket2 + 43), pAggrPacketsSize - 43);
+		if ((pAggrPacketsSize - 43) != nBytesSent)
+		{
+			LOG_MSG_ERROR("Sending packet into the USB pipe(%d bytes) "
+					"failed!\n", pAggrPacketsSize - 43);
+			return false;
+		}
+		/* This is deaggregation exception packet, this packet should not arrive at this pipe */
+		LOG_MSG_DEBUG("Reading packet from the USB pipe(0 bytes should be there)\n");
+		nBytesReceived = m_IpaToUsbPipe.Receive(pReceivedPacket, MAX_PACKET_SIZE);
+		if (0 != nBytesReceived)
+		{
+			LOG_MSG_ERROR("Receiving aggregated packet from the USB pipe(%d bytes) "
+					"failed!\n", nBytesReceived);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+
+		/* Create a frame of size 1024 bytes */
+		pAggrPacketsSize = 0;
+		for(int i = 0; i < 8; i++) {
+			//initialize the packets
+			//Load input data (RNDIS packet) from file
+			pIpPacketsSize = MAX_PACKET_SIZE;
+			if (!RNDISAggregationHelper::LoadRNDISPacket(m_eIP, pPacket3 + pAggrPacketsSize, pIpPacketsSize))
+			{
+				LOG_MSG_ERROR("Failed to load Ethernet Packet");
+				return false;
+			}
+			pAggrPacketsSize += pIpPacketsSize;
+			nIPv4DSTAddr = ntohl(0x7F000001);
+			memcpy (&((pPacket3 + i * pIpPacketsSize)[IPV4_DST_ADDR_OFFSET_IN_RNDIS]),&nIPv4DSTAddr,
+					sizeof(nIPv4DSTAddr));
+		}
+		print_buff(pPacket3, pAggrPacketsSize);
+
+		/* Send the 5th frame */
+		LOG_MSG_ERROR("blend-3 Sending packet into the A2 TETH pipe(%d bytes)\n",
+						pAggrPacketsSize);
+		nBytesSent = m_UsbToIpaPipeDeagg.Send(pPacket3, pAggrPacketsSize);
+		if (pAggrPacketsSize  != nBytesSent)
+		{
+			LOG_MSG_ERROR("Sending packet into the USB pipe(%d bytes) "
+				"failed!\n", pAggrPacketsSize);
+			return false;
+		}
+
+		for(int i = 0; i < 8; i++) {
+			//Receive the packet, one by one
+			LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be there)"
+					"\n", pIpPacketsSize - sizeof(struct RndisHeader));
+			size_t nBytesReceived = m_IpaToUsbPipe.Receive(pReceivedPacket, MAX_PACKET_SIZE);
+			if (pIpPacketsSize - sizeof(struct RndisHeader) != nBytesReceived)
+			{
+				LOG_MSG_ERROR("Receiving aggregated packet from the USB pipe(%d bytes) "
+						"failed!\n", nBytesReceived);
+				print_buff(pReceivedPacket, nBytesReceived);
+				return false;
+			}
+			if (!RNDISAggregationHelper::CompareEthervsRNDISPacket(pReceivedPacket,
+										nBytesReceived,
+										pPacket3 + i * pIpPacketsSize,
+										pIpPacketsSize))
+				return false;
+		}
+
+		return true;
+	}
+
+};
+
+class RNDISAggregationPacketLimitTest: public RNDISAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	RNDISAggregationPacketLimitTest()
+	{
+		m_name = "RNDISAggregationPacketLimitTest";
+		m_description = "RNDISAggregationPacketLimitTest - Send 2 IP packet "
+			"and expect aggregated RNDIS packet.";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	virtual bool AddRules()
+	{
+		return AddRulesAggPacketLimit();
+	} // AddRules()
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool TestLogic()
+	{
+		//The packets that will be sent
+
+		Byte pPackets[2][MAX_PACKET_SIZE];
+		//Buffer for the packet that will be received
+		Byte pReceivedPacket[2*MAX_PACKET_SIZE];
+		//Total size of all sent packets (this is the max size of the aggregated
+		//packet minus the size of the header and the NDP)
+		uint32_t nIPv4DSTAddr;
+		size_t pIpPacketsSizes[2];
+		size_t ExpectedPacketSize = 2 * sizeof(struct RndisEtherHeader);
+
+		for(int i = 0; i < 2; i++) {
+			//initialize the packets
+			// Load input data (IP packet) from file
+			pIpPacketsSizes[i] = MAX_PACKET_SIZE;
+			if (!LoadDefaultPacket(m_eIP, pPackets[i], pIpPacketsSizes[i]))
+			{
+				LOG_MSG_ERROR("Failed to load Ethernet Packet");
+				return false;
+			}
+			nIPv4DSTAddr = ntohl(0x7F000001);
+			memcpy (&pPackets[i][IPV4_DST_ADDR_OFFSET],&nIPv4DSTAddr,
+				sizeof(nIPv4DSTAddr));
+
+			//send the packet
+			LOG_MSG_DEBUG("Sending packet into the A2 TETH pipe(%d bytes)\n",
+				pIpPacketsSizes[i]);
+			size_t nBytesSent = m_HsicToIpaPipe.Send(pPackets[i], pIpPacketsSizes[i]);
+			if (pIpPacketsSizes[i] != nBytesSent)
+			{
+				LOG_MSG_ERROR("Sending packet into the USB pipe(%d bytes) "
+					"failed!\n", pIpPacketsSizes[i]);
+				return false;
+			}
+			ExpectedPacketSize += pIpPacketsSizes[i];
+		}
+
+		//receive the packet
+		LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be there)"
+			"\n", ExpectedPacketSize);
+		size_t nBytesReceived = m_IpaToUsbPipeAggPktLimit.Receive(pReceivedPacket, MAX_PACKET_SIZE);
+		if (ExpectedPacketSize != nBytesReceived)
+		{
+			LOG_MSG_ERROR("Receiving aggregated packet from the USB pipe(%d bytes) "
+				"failed!\n", nBytesReceived);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+
+
+		for(int i = 0; i < 2; i++) {
+			if (!RNDISAggregationHelper::CompareIPvsRNDISPacket(pPackets[i], pIpPacketsSizes[i],
+				pReceivedPacket + (i * ExpectedPacketSize / 2), ExpectedPacketSize / 2))
+				return false;
+		}
+
+		return true;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+
+
+static RNDISAggregationSanityTest aRNDISAggregationSanityTest;
+static RNDISAggregationDeaggregation1PacketTest aRNDISAggregationDeaggregation1PacketTest;
+static RNDISAggregation1PacketTest aRNDISAggregation1PacketTest;
+static RNDISAggregationSuspendWaTest aRNDISAggregationSuspendWaTest;
+static RNDISAggregationByteLimitTest aRNDISAggregationByteLimitTest;
+static RNDISAggregationByteLimitTestFC aRNDISAggregationByteLimitTestFC;
+static RNDISAggregationDualDpTestFC aRNDISAggregationDualDpTestFC;
+static RNDISAggregationDualDpTestFcRoutingBased aRNDISAggregationDualDpTestFcRoutingBased;
+static RNDISAggregationDeaggregationNumPacketsTest aRNDISAggregationDeaggregationNumPacketsTest;
+static RNDISAggregationDeaggregationExceptionPacketsTest aRNDISAggregationDeaggregationExceptionPacketsTest;
+static RNDISAggregationPacketLimitTest aRNDISAggregationPacketLimitTest;
+
+/////////////////////////////////////////////////////////////////////////////////
+//                                  EOF                                      ////
+/////////////////////////////////////////////////////////////////////////////////

+ 183 - 0
kernel-tests/RoutingDriverWrapper.cpp

@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "RoutingDriverWrapper.h"
+#include "TestsUtils.h"
+
+const char* RoutingDriverWrapper::DEVICE_NAME = "/dev/ipa";
+
+RoutingDriverWrapper::RoutingDriverWrapper()
+{
+	m_fd = open(DEVICE_NAME, O_RDWR);
+	if (0 == m_fd) {
+		printf("Failed opening %s.\n", DEVICE_NAME);
+	}
+}
+
+RoutingDriverWrapper::~RoutingDriverWrapper()
+{
+	close(m_fd);
+}
+
+bool RoutingDriverWrapper::DeviceNodeIsOpened()
+{
+	int res = fcntl(m_fd, F_GETFL);
+
+	if (m_fd > 0 && res >=0)
+		return true;
+	else
+		return false;
+
+}
+
+bool RoutingDriverWrapper::AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened())
+		return false;
+
+	retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE, ruleTable);
+	if (retval) {
+		printf("%s(), failed adding routing rule table %p\n", __FUNCTION__, ruleTable);
+		return false;
+	}
+
+	printf("%s(), Added routing rule table %p\n", __FUNCTION__, ruleTable);
+	return true;
+}
+
+bool RoutingDriverWrapper::AddRoutingRule(struct ipa_ioc_add_rt_rule_v2 *ruleTable_v2)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened())
+		return false;
+
+	retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE_V2, ruleTable_v2);
+	if (retval) {
+		printf("%s(), failed adding routing rule table %p\n", __FUNCTION__, ruleTable_v2);
+		return false;
+	}
+
+	printf("%s(), Added routing rule table %p\n", __FUNCTION__, ruleTable_v2);
+	return true;
+}
+
+bool RoutingDriverWrapper::DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened())
+		return false;
+
+	retval = ioctl(m_fd, IPA_IOC_DEL_RT_RULE, ruleTable);
+	if (retval) {
+		printf("%s(), failed deleting routing rule table %p\n", __FUNCTION__, ruleTable);
+		return false;
+	}
+
+	printf("%s(), Deleted routing rule table %p\n", __FUNCTION__, ruleTable);
+	return true;
+}
+
+bool RoutingDriverWrapper::Commit(enum ipa_ip_type ip)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened())
+		return false;
+
+	retval = ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
+	if (retval) {
+		printf("%s(), failed commiting routing rules.\n", __FUNCTION__);
+		return false;
+	}
+
+	printf("%s(), Commited routing rules to IPA HW.\n", __FUNCTION__);
+	return true;
+}
+
+bool RoutingDriverWrapper::Reset(enum ipa_ip_type ip)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened())
+		return false;
+
+	retval = ioctl(m_fd, IPA_IOC_RESET_RT, ip);
+	retval |= ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
+	if (retval) {
+		printf("%s(), failed reseting routing block.\n", __FUNCTION__);
+		return false;
+	}
+
+	printf("%s(), Reset command issued to IPA routing block.\n", __FUNCTION__);
+	return true;
+}
+
+bool RoutingDriverWrapper::GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened())
+		return false;
+
+	retval = ioctl(m_fd, IPA_IOC_GET_RT_TBL, routingTable);
+	if (retval) {
+		printf("%s(), IPA_IOCTL_GET_RT_TBL ioctl failed, routingTable =0x%p, retval=0x%x.\n", __FUNCTION__, routingTable, retval);
+		return false;
+	}
+
+	printf("%s(), IPA_IOCTL_GET_RT_TBL ioctl issued to IPA routing block.\n", __FUNCTION__);
+	return true;
+}
+
+bool RoutingDriverWrapper::PutRoutingTable(uint32_t routingTableHandle)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened())
+		return false;
+
+	retval = ioctl(m_fd, IPA_IOC_PUT_RT_TBL, routingTableHandle);
+	if (retval) {
+		printf("%s(), IPA_IOCTL_PUT_RT_TBL ioctl failed.\n", __FUNCTION__);
+		return false;
+	}
+
+	printf("%s(), IPA_IOCTL_PUT_RT_TBL ioctl issued to IPA routing block.\n", __FUNCTION__);
+	return true;
+}
+

+ 63 - 0
kernel-tests/RoutingDriverWrapper.h

@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ROUTING_H_
+#define ROUTING_H_
+
+#include <stdint.h>
+#include "linux/msm_ipa.h"
+
+using namespace std;
+
+class RoutingDriverWrapper
+{
+public:
+	RoutingDriverWrapper();
+	~RoutingDriverWrapper();
+
+	bool AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable);
+	bool AddRoutingRule(ipa_ioc_add_rt_rule_v2 *ruleTable_v2);
+	bool DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable);
+
+	bool Commit(enum ipa_ip_type ip);
+	bool Reset(enum ipa_ip_type ip);
+
+	bool GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable);
+	bool PutRoutingTable(uint32_t routingTableHandle);
+
+	bool DeviceNodeIsOpened();
+
+private:
+	static const char *DEVICE_NAME;
+	/* File descriptor of the IPA device node /dev/ipa*/
+	int m_fd;
+};
+
+#endif
+

+ 5133 - 0
kernel-tests/RoutingTests.cpp

@@ -0,0 +1,5133 @@
+/*
+ * Copyright (c) 2017-2018,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include "hton.h" // for htonl
+
+
+#include "InterfaceAbstraction.h"
+#include "Constants.h"
+#include "Logger.h"
+#include "TestsUtils.h"
+#include "linux/msm_ipa.h"
+#include "RoutingDriverWrapper.h"
+#include "Filtering.h"
+#include "IPAFilteringTable.h"
+
+#define TOS_FIELD_OFFSET (1)
+#define DST_ADDR_LSB_OFFSET_IPV4 (19)
+#define SRC_ADDR_LSB_OFFSET_IPV4 (15)
+#define DST_ADDR_MSB_OFFSET_IPV6 (24)
+#define DST_ADDR_LSB_OFFSET_IPV6 (39)
+#define TRAFFIC_CLASS_MSB_OFFSET_IPV6 (0)
+#define TRAFFIC_CLASS_LSB_OFFSET_IPV6 (1)
+#define FLOW_CLASS_MSB_OFFSET_IPV6 (1)
+#define FLOW_CLASS_MB_OFFSET_IPV6 (2)
+#define FLOW_CLASS_LSB_OFFSET_IPV6 (3)
+#define IPV4_DST_PORT_OFFSET (20+2)
+#define IPV6_SRC_PORT_OFFSET (40)
+#define IPV6_DST_PORT_OFFSET (40+2)
+#define IPv4_TCP_FLAGS_OFFSET (20+13)
+#define IPv6_TCP_FLAGS_OFFSET (40+13)
+
+#define TCP_ACK_FLAG_MASK (0x10)
+
+extern Logger g_Logger;
+
+class IpaRoutingBlockTestFixture:public TestBase
+{
+public:
+	IpaRoutingBlockTestFixture():
+		m_sendSize (BUFF_MAX_SIZE),
+		m_sendSize2 (BUFF_MAX_SIZE),
+		m_sendSize3 (BUFF_MAX_SIZE),
+		m_IpaIPType(IPA_IP_v4)
+	{
+		memset(m_sendBuffer, 0, sizeof(m_sendBuffer));
+		memset(m_sendBuffer2, 0, sizeof(m_sendBuffer2));
+		memset(m_sendBuffer3, 0, sizeof(m_sendBuffer3));
+		m_testSuiteName.push_back("Routing");
+	}
+
+	static int SetupKernelModule(bool en_status = false)
+	{
+		int retval;
+		struct ipa_channel_config from_ipa_channels[3];
+		struct test_ipa_ep_cfg from_ipa_cfg[3];
+		struct ipa_channel_config to_ipa_channels[1];
+		struct test_ipa_ep_cfg to_ipa_cfg[1];
+
+		struct ipa_test_config_header header = {0};
+		struct ipa_channel_config *to_ipa_array[1];
+		struct ipa_channel_config *from_ipa_array[3];
+
+		/* From ipa configurations - 3 pipes */
+		memset(&from_ipa_cfg[0], 0, sizeof(from_ipa_cfg[0]));
+		prepare_channel_struct(&from_ipa_channels[0],
+				header.from_ipa_channels_num++,
+				IPA_CLIENT_TEST2_CONS,
+				(void *)&from_ipa_cfg[0],
+				sizeof(from_ipa_cfg[0]), en_status);
+		from_ipa_array[0] = &from_ipa_channels[0];
+
+		memset(&from_ipa_cfg[1], 0, sizeof(from_ipa_cfg[1]));
+		prepare_channel_struct(&from_ipa_channels[1],
+				header.from_ipa_channels_num++,
+				IPA_CLIENT_TEST3_CONS,
+				(void *)&from_ipa_cfg[1],
+				sizeof(from_ipa_cfg[1]), en_status);
+		from_ipa_array[1] = &from_ipa_channels[1];
+
+		memset(&from_ipa_cfg[2], 0, sizeof(from_ipa_cfg[2]));
+		prepare_channel_struct(&from_ipa_channels[2],
+				header.from_ipa_channels_num++,
+				IPA_CLIENT_TEST4_CONS,
+				(void *)&from_ipa_cfg[2],
+				sizeof(from_ipa_cfg[2]), en_status);
+		from_ipa_array[2] = &from_ipa_channels[2];
+
+		/* To ipa configurations - 1 pipes */
+		memset(&to_ipa_cfg[0], 0, sizeof(to_ipa_cfg[0]));
+		prepare_channel_struct(&to_ipa_channels[0],
+				header.to_ipa_channels_num++,
+				IPA_CLIENT_TEST_PROD,
+				(void *)&to_ipa_cfg[0],
+				sizeof(to_ipa_cfg[0]));
+		to_ipa_array[0] = &to_ipa_channels[0];
+
+		prepare_header_struct(&header, from_ipa_array, to_ipa_array);
+
+		retval = GenericConfigureScenario(&header);
+
+		return retval;
+	}
+
+	bool Setup(bool en_status)
+	{
+		bool bRetVal = true;
+
+		bRetVal = SetupKernelModule(en_status);
+		if (bRetVal != true) {
+			return bRetVal;
+		}
+		m_producer.Open(INTERFACE0_TO_IPA_DATA_PATH, INTERFACE0_FROM_IPA_DATA_PATH);
+
+		m_consumer.Open(INTERFACE1_TO_IPA_DATA_PATH, INTERFACE1_FROM_IPA_DATA_PATH);
+		m_consumer2.Open(INTERFACE2_TO_IPA_DATA_PATH, INTERFACE2_FROM_IPA_DATA_PATH);
+		m_defaultConsumer.Open(INTERFACE3_TO_IPA_DATA_PATH, INTERFACE3_FROM_IPA_DATA_PATH);
+
+		if (!m_routing.DeviceNodeIsOpened()) {
+			printf("Routing block is not ready for immediate commands!\n");
+			return false;
+		}
+
+		if (!m_filtering.DeviceNodeIsOpened()) {
+			printf("Filtering block is not ready for immediate commands!\n");
+			return false;
+		}
+		m_routing.Reset(IPA_IP_v4);
+		m_routing.Reset(IPA_IP_v6);
+
+		return true;
+	} /* Setup()*/
+
+	bool Setup()
+	{
+		return Setup(false);
+	}
+
+	bool Teardown()
+	{
+		if (!m_routing.DeviceNodeIsOpened()) {
+			printf("Routing block is not ready for immediate commands!\n");
+			return false;
+		}
+		if (!m_filtering.DeviceNodeIsOpened()) {
+			printf("Filtering block is not ready for immediate commands!\n");
+			return false;
+		}
+
+		m_producer.Close();
+		m_consumer.Close();
+		m_consumer2.Close();
+		m_defaultConsumer.Close();
+
+		return true;
+	} /* Teardown() */
+
+	bool LoadFiles(enum ipa_ip_type ip)
+	{
+		string fileName;
+
+		if (IPA_IP_v4 == ip) {
+			fileName = "Input/IPv4_1";
+		} else {
+			fileName = "Input/IPv6";
+		}
+
+		if (!LoadDefaultPacket(ip, m_sendBuffer, m_sendSize)) {
+			LOG_MSG_ERROR("Failed loading default Packet");
+			return false;
+		}
+
+		if (!LoadDefaultPacket(ip, m_sendBuffer2, m_sendSize2)) {
+			LOG_MSG_ERROR("Failed loading default Packet");
+			return false;
+		}
+
+		if (!LoadDefaultPacket(ip, m_sendBuffer3, m_sendSize3)) {
+			LOG_MSG_ERROR("Failed loading default Packet");
+			return false;
+		}
+
+		return true;
+	}
+
+	bool ReceivePacketAndCompareFrom(InterfaceAbstraction& cons, Byte* send,
+									 size_t send_sz, bool shouldBeHit)
+	{
+		size_t receivedSize = 0;
+		bool isSuccess = true;
+
+		/* Receive results*/
+		Byte *rxBuff1 = new Byte[0x400];
+
+		if (NULL == rxBuff1)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = cons.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, cons.m_fromChannelName.c_str());
+
+		// Compare results
+		isSuccess &= CompareResultVsGolden_w_Status(send,  send_sz,  rxBuff1, receivedSize);
+
+		if (shouldBeHit) {
+			isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+				IsCacheHit_v5_0(send_sz, receivedSize, rxBuff1) : IsCacheHit(send_sz, receivedSize, rxBuff1);
+		}
+		else
+		{
+			isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+				IsCacheMiss_v5_0(send_sz, receivedSize, rxBuff1) : IsCacheMiss(send_sz, receivedSize, rxBuff1);
+		}
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+//		char * p = recievedBuffer;
+		size_t j;
+		for(j = 0; j < m_sendSize; j++)
+			snprintf(&sentBuffer[3 * j], sentBufferSize - (3 * j + 1), " %02X", send[j]);
+		for(j = 0; j < receivedSize; j++)
+//			recievedBuffer += sprintf(recievedBuffer, "%02X", rxBuff1[i]);
+		    snprintf(&recievedBuffer[3 * j], recievedBufferSize - (3 * j + 1), " %02X", rxBuff1[j]);
+		printf("Expected Value (%zu)\n%s\n, Received Value1(%zu)\n%s\n",send_sz,sentBuffer,receivedSize,recievedBuffer);
+
+		delete[] rxBuff1;
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		return isSuccess;
+	}
+
+	bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool pkt1_cmp_succ, pkt2_cmp_succ, pkt3_cmp_succ;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		memset(rxBuff1, 0, 0x400);
+		memset(rxBuff2, 0, 0x400);
+		memset(rxBuff3, 0, 0x400);
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer2.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer2.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		/* Compare results */
+		pkt1_cmp_succ = CompareResultVsGolden(m_sendBuffer,  m_sendSize,  rxBuff1, receivedSize);
+		pkt2_cmp_succ = CompareResultVsGolden(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+		pkt3_cmp_succ = CompareResultVsGolden(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		size_t recievedBufferSize =
+			MAX3(receivedSize, receivedSize2, receivedSize3) * 3;
+		size_t sentBufferSize =
+			MAX3(m_sendSize, m_sendSize2, m_sendSize3) * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		if (NULL == recievedBuffer || NULL == sentBuffer) {
+			printf("Memory allocation error\n");
+			return false;
+		}
+
+		size_t j;
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+		for(j = 0; j < m_sendSize; j++)
+		    snprintf(&sentBuffer[3 * j], sentBufferSize - (3 * j + 1), " %02X", m_sendBuffer[j]);
+		for(j = 0; j < receivedSize; j++)
+		    snprintf(&recievedBuffer[3 * j], recievedBufferSize - (3 * j + 1), " %02X", rxBuff1[j]);
+		printf("Expected Value1(%zu)\n%s\n, Received Value1(%zu)\n%s\n-->Value1 %s\n",
+			m_sendSize,sentBuffer,receivedSize,recievedBuffer,
+			pkt1_cmp_succ?"Match":"no Match");
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+		for(j = 0; j < m_sendSize2; j++)
+		    snprintf(&sentBuffer[3 * j], sentBufferSize - (3 * j + 1), " %02X", m_sendBuffer2[j]);
+		for(j = 0; j < receivedSize2; j++)
+		    snprintf(&recievedBuffer[3 * j], recievedBufferSize - (3 * j + 1), " %02X", rxBuff2[j]);
+		printf("Expected Value2 (%zu)\n%s\n, Received Value2(%zu)\n%s\n-->Value2 %s\n",
+			m_sendSize2,sentBuffer,receivedSize2,recievedBuffer,
+			pkt2_cmp_succ?"Match":"no Match");
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+		for(j = 0; j < m_sendSize3; j++)
+		    snprintf(&sentBuffer[3 * j], sentBufferSize - (3 * j + 1), " %02X", m_sendBuffer3[j]);
+		for(j = 0; j < receivedSize3; j++)
+		    snprintf(&recievedBuffer[3 * j], recievedBufferSize - (3 * j + 1), " %02X", rxBuff3[j]);
+		printf("Expected Value3 (%zu)\n%s\n, Received Value3(%zu)\n%s\n-->Value3 %s\n",
+			m_sendSize3,sentBuffer,receivedSize3,recievedBuffer,
+			pkt3_cmp_succ?"Match":"no Match");
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return pkt1_cmp_succ && pkt2_cmp_succ && pkt3_cmp_succ;
+	}
+
+	void print_packets(size_t receivedSize, size_t m_sendSize, size_t recievedBufferSize, size_t sentBufferSize, Byte *rxBuff, Byte *m_sendBuffer,  char *recievedBuffer, char *sentBuffer)
+	{
+		size_t j;
+
+		for(j = 0; j < m_sendSize; j++) {
+			snprintf(&sentBuffer[3 * j], sentBufferSize - 3 * j,
+				" %02X", m_sendBuffer[j]);
+		}
+		for(j = 0; j < receivedSize; j++) {
+			snprintf(&recievedBuffer[3 * j], recievedBufferSize- 3 * j,
+				" %02X", rxBuff[j]);
+		}
+		printf("Expected Value (%zu)\n%s\n, Received Value(%zu)\n%s\n",m_sendSize,sentBuffer,receivedSize,recievedBuffer);
+	}
+
+	~IpaRoutingBlockTestFixture()
+	{
+		m_sendSize = 0;
+		m_sendSize2 = 0;
+		m_sendSize3 = 0;
+	}
+
+	void InitFilteringBlock()
+	{
+		IPAFilteringTable fltTable;
+		struct ipa_ioc_get_rt_tbl st_rt_tbl;
+		struct ipa_flt_rule_add flt_rule_entry;
+
+		memset(&st_rt_tbl, 0, sizeof(st_rt_tbl));
+		memset(&flt_rule_entry, 0, sizeof(flt_rule_entry));
+		strlcpy(st_rt_tbl.name, "LAN", sizeof(st_rt_tbl.name));
+		st_rt_tbl.ip = m_IpaIPType;
+		fltTable.Init(m_IpaIPType, IPA_CLIENT_TEST_PROD, false, 1);
+		m_routing.GetRoutingTable(&st_rt_tbl);
+		flt_rule_entry.rule.rt_tbl_hdl = st_rt_tbl.hdl;
+		fltTable.AddRuleToTable(flt_rule_entry);
+		m_filtering.AddFilteringRule(fltTable.GetFilteringTable());
+	}
+
+	inline bool VerifyStatusReceived(size_t SendSize, size_t RecvSize)
+	{
+		size_t stts_size = sizeof(struct ipa3_hw_pkt_status);
+
+		if (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) {
+			stts_size = sizeof(struct ipa3_hw_pkt_status_hw_v5_0);
+		}
+
+		if ((RecvSize <= SendSize) ||
+			((RecvSize - SendSize) != stts_size)){
+			printf("received buffer size does not match! sent:receive [%zu]:[%zu]\n",SendSize,RecvSize);
+			return false;
+		}
+
+		return true;
+	}
+
+	inline bool IsCacheHit(size_t SendSize, size_t RecvSize, void *Buff)
+	{
+		struct ipa3_hw_pkt_status *pStatus = (struct ipa3_hw_pkt_status *)Buff;
+
+		if (VerifyStatusReceived(SendSize,RecvSize) == false){
+			return false;
+		}
+
+		if((bool)pStatus->route_hash){
+			printf ("%s::cache hit!! \n",__FUNCTION__);
+			return true;
+		}
+
+		printf ("%s::cache miss!! \n",__FUNCTION__);
+		return false;
+
+	}
+
+	inline bool IsCacheHit_v5_0(size_t SendSize, size_t RecvSize, void *Buff)
+	{
+		struct ipa3_hw_pkt_status_hw_v5_0 *pStatus = (struct ipa3_hw_pkt_status_hw_v5_0 *)Buff;
+
+		if (VerifyStatusReceived(SendSize,RecvSize) == false){
+			return false;
+		}
+
+		if((bool)pStatus->route_hash){
+			printf ("%s::cache hit!! \n",__FUNCTION__);
+			return true;
+		}
+
+		printf ("%s::cache miss!! \n",__FUNCTION__);
+		return false;
+
+	}
+
+	inline bool IsCacheMiss(size_t SendSize, size_t RecvSize, void *Buff)
+	{
+		struct ipa3_hw_pkt_status *pStatus = (struct ipa3_hw_pkt_status *)Buff;
+
+		if (VerifyStatusReceived(SendSize,RecvSize) == false){
+			return false;
+		}
+
+		if(!((bool)pStatus->route_hash)){
+			printf ("%s::cache miss!! \n",__FUNCTION__);
+			return true;
+		}
+
+		printf ("%s::cache hit!! \n",__FUNCTION__);
+		return false;
+	}
+
+		inline bool IsCacheMiss_v5_0(size_t SendSize, size_t RecvSize, void *Buff)
+	{
+		struct ipa3_hw_pkt_status_hw_v5_0 *pStatus = (struct ipa3_hw_pkt_status_hw_v5_0 *)Buff;
+
+		if (VerifyStatusReceived(SendSize,RecvSize) == false){
+			return false;
+		}
+
+		if(!((bool)pStatus->route_hash)){
+			printf ("%s::cache miss!! \n",__FUNCTION__);
+			return true;
+		}
+
+		printf ("%s::cache hit!! \n",__FUNCTION__);
+		return false;
+	}
+
+	static RoutingDriverWrapper m_routing;
+	static Filtering m_filtering;
+
+	static const size_t BUFF_MAX_SIZE = 1024;
+
+	InterfaceAbstraction m_producer;
+	InterfaceAbstraction m_consumer;
+	InterfaceAbstraction m_consumer2;
+	InterfaceAbstraction m_defaultConsumer;
+	Byte m_sendBuffer[BUFF_MAX_SIZE];	// First input file / IP packet
+	Byte m_sendBuffer2[BUFF_MAX_SIZE];	// Second input file / IP packet
+	Byte m_sendBuffer3[BUFF_MAX_SIZE];	// Third input file (default) / IP packet
+	size_t m_sendSize;
+	size_t m_sendSize2;
+	size_t m_sendSize3;
+	enum ipa_ip_type m_IpaIPType;
+
+
+private:
+};
+
+RoutingDriverWrapper IpaRoutingBlockTestFixture::m_routing;
+Filtering IpaRoutingBlockTestFixture::m_filtering;
+
+/*---------------------------------------------------------------------------*/
+/* Test1: Tests routing by destination address							     */
+/*---------------------------------------------------------------------------*/
+class IpaRoutingBlockTest1 : public IpaRoutingBlockTestFixture
+{
+public:
+	IpaRoutingBlockTest1()
+	{
+		m_name = "IpaRoutingBlockTest1";
+		m_description =" \
+		Routing block test 001 - Destination address exact match\1. Generate and commit a single routing tables. \
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP == (192.169.2.170 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All DST_IP == (192.168.2.255 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v4;
+		Register(*this);
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("Failed memory allocation for rt_rule\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v4;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802FF;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AA;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test2: Tests routing by destination address with a subnet (mask) */
+/*---------------------------------------------------------------------------*/
+class IpaRoutingBlockTest2 : IpaRoutingBlockTestFixture
+{
+public:
+	IpaRoutingBlockTest2()
+	{
+		m_name = "IpaRoutingBlockTest2";
+		m_description =" \
+		Routing block test 002 - Destination address subnet match \
+		1. Generate and commit a single routing tables. \
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP == (192.169.170.0 & 255.255.255.0)traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All DST_IP == (192.168.255.0 & 255.255.255.0)traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v4;
+		Register(*this);
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		printf("ENTRY: IpaRoutingBlockTest2::Run()\n");
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[18] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[18] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		printf("ENTRY: IpaRoutingBlockTest2::AddRules()\n");
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("fail\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v4;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A8FF00;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFF00;
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A8AA00;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFF00;
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		printf("Before calling m_routing.AddRoutingRule()\n");
+		printf("m_routing = %p\n", &m_routing);
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+};
+
+
+/*---------------------------------------------------------------------------*/
+/* Test3: Tests routing by TOS (Type Of Service) */
+/*---------------------------------------------------------------------------*/
+class IpaRoutingBlockTest3 : IpaRoutingBlockTestFixture
+{
+public:
+	IpaRoutingBlockTest3()
+	{
+		m_name = "IpaRoutingBlockTest3";
+		m_description = " \
+		Routing block test 003 - TOS exact match\
+		1. Generate and commit a single routing tables. \
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All TOS == 0xBF traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All TOS == 0x3A traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v4;
+		Register(*this);
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[TOS_FIELD_OFFSET] = 0xBF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[TOS_FIELD_OFFSET] = 0x3A;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if (!rt_rule) {
+			printf("fail\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v4;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl;
+		// gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_TOS;
+		rt_rule_entry->rule.attrib.u.v4.tos = 0xBF;
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_TOS;
+		rt_rule_entry->rule.attrib.u.v4.tos = 0x3A;
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test4: Destination address exact match and TOS exact match */
+/*---------------------------------------------------------------------------*/
+class IpaRoutingBlockTest4 : IpaRoutingBlockTestFixture
+{
+public:
+	IpaRoutingBlockTest4()
+	{
+		m_name = "IpaRoutingBlockTest4";
+		m_description =" \
+		Routing block test 004 - Source and Destination address and TOS exact match \
+		1. Generate and commit a single routing tables. \
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP == (192.169.2.255 & 255.255.255.255) and TOS == 0xFF traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All DST_IP == (192.168.2.170 & 255.255.255.255) and TOS == 0xAA traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All DST_IP == (192.168.2.85 & 255.255.255.255) and SRC_IP == (192.168.2.241 & 255.255.255.255) TOS == 0x24 traffic goes to pipe IPA_CLIENT_TEST3_CONS";
+		m_IpaIPType = IPA_IP_v4;
+		Register(*this);
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[TOS_FIELD_OFFSET] = 0xFF;
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[TOS_FIELD_OFFSET] = 0xAA;
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		m_sendBuffer3[TOS_FIELD_OFFSET] = 0x24;
+		m_sendBuffer3[DST_ADDR_LSB_OFFSET_IPV4] = 0x55;
+		m_sendBuffer3[SRC_ADDR_LSB_OFFSET_IPV4] = 0xF1;
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("fail\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v4;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_TOS | IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.tos = 0xFF;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802FF;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_TOS | IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.tos = 0xAA;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AA;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_TOS | IPA_FLT_DST_ADDR | IPA_FLT_SRC_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.tos = 0x24;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A80255;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v4.src_addr      = 0xC0A802F1;
+		rt_rule_entry->rule.attrib.u.v4.src_addr_mask = 0xFFFFFFFF;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test5: IPv6 - Tests routing by destination address */
+/*---------------------------------------------------------------------------*/
+class IpaRoutingBlockTest5 : public IpaRoutingBlockTestFixture
+{
+public:
+	IpaRoutingBlockTest5()
+	{
+		m_name = "IpaRoutingBlockTest5";
+		m_description =" \
+		Routing block test 005 - IPv6 Destination address exact match \
+		1. Generate and commit a single routing tables. \
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000FF \
+		traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+		All DST_IP ==	0XFF020000 \
+						0x00000000 \
+						0x00000000 \
+						0X000000FF \
+		traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+		All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v6;
+		Register(*this);
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("fail\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v6;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0]      = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3]      = 0X000000FF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0]      = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3]      = 0X000000AA;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test6: IPv6 - Tests routing by destination address */
+/*---------------------------------------------------------------------------*/
+class IpaRoutingBlockTest006 : public IpaRoutingBlockTestFixture
+{
+public:
+	IpaRoutingBlockTest006()
+	{
+		m_name = "IpaRoutingBlockTest006";
+		m_description =" \
+		Routing block test 006 - IPv6 Destination address Subnet match \
+		1. Generate and commit a single routing tables. \
+		2. Generate and commit Three routing rules: (DST & Mask Match 0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x0000000). \
+			All DST_IP ==	0X11020000 \
+							0x00000000 \
+							0x00000000 \
+							0X0000000C \
+		traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+		All DST_IP ==	0X22020000 \
+						0x00000000 \
+						0x00000000 \
+						0X0000000C \
+		traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+		All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v6;
+		Register(*this);
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_MSB_OFFSET_IPV6] = 0x11;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_MSB_OFFSET_IPV6] = 0x22;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("fail\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v6;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // TODO: Header Insertion gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0]      = 0X11020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3]      = 0X0000000C;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // TODO: Header Insertion gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0]      = 0X22020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3]      = 0X0000000C;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test7: IPv6 - Tests routing by destination address */
+/*---------------------------------------------------------------------------*/
+class IpaRoutingBlockTest007 : public IpaRoutingBlockTestFixture
+{
+public:
+	IpaRoutingBlockTest007()
+	{
+		m_name = "IpaRoutingBlockTest007";
+		m_description = " \
+		Routing block test 007 - IPv6 Exact Traffic Class Match \
+		1. Generate and commit a single routing tables. \
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All Traffic Class == 0xAA traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All Traffic Class == 0xBB traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v6;
+		Register(*this);
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[TRAFFIC_CLASS_MSB_OFFSET_IPV6] &= 0xF0;
+		m_sendBuffer[TRAFFIC_CLASS_MSB_OFFSET_IPV6] |= 0x0A;
+		m_sendBuffer[TRAFFIC_CLASS_LSB_OFFSET_IPV6] &= 0x0F;
+		m_sendBuffer[TRAFFIC_CLASS_LSB_OFFSET_IPV6] |= 0xA0;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[TRAFFIC_CLASS_MSB_OFFSET_IPV6] &= 0xF0;
+		m_sendBuffer2[TRAFFIC_CLASS_MSB_OFFSET_IPV6] |= 0x0B;
+		m_sendBuffer2[TRAFFIC_CLASS_LSB_OFFSET_IPV6] &= 0x0F;
+		m_sendBuffer2[TRAFFIC_CLASS_LSB_OFFSET_IPV6] |= 0xB0;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("fail\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v6;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // TODO: Header Insertion gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_TC;
+		rt_rule_entry->rule.attrib.u.v6.tc = 0xAA;
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // TODO: Header Insertion gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_TC;
+		rt_rule_entry->rule.attrib.u.v6.tc = 0xBB;
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test8: IPv6 - Tests routing by destination address */
+/*---------------------------------------------------------------------------*/
+class IpaRoutingBlockTest008 : public IpaRoutingBlockTestFixture
+{
+public:
+	IpaRoutingBlockTest008()
+	{
+		m_name = "IpaRoutingBlockTest008";
+		m_description = " \
+		Routing block test 008 - IPv6 Destination address exact match and Traffic Class Match \
+		1. Generate and commit a single routing tables. \
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All Traffic Class == 0xAA & IPv6 DST Addr 0xFF020000...00AA traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All Traffic Class == 0xBB & IPv6 DST Addr 0xFF020000...00BB traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v6;
+		Register(*this);
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[TRAFFIC_CLASS_MSB_OFFSET_IPV6] &= 0xF0;
+		m_sendBuffer[TRAFFIC_CLASS_MSB_OFFSET_IPV6] |= 0x0A;
+		m_sendBuffer[TRAFFIC_CLASS_LSB_OFFSET_IPV6] &= 0x0F;
+		m_sendBuffer[TRAFFIC_CLASS_LSB_OFFSET_IPV6] |= 0xA0;
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[TRAFFIC_CLASS_MSB_OFFSET_IPV6] &= 0xF0;
+		m_sendBuffer2[TRAFFIC_CLASS_MSB_OFFSET_IPV6] |= 0x0B;
+		m_sendBuffer2[TRAFFIC_CLASS_LSB_OFFSET_IPV6] &= 0x0F;
+		m_sendBuffer2[TRAFFIC_CLASS_LSB_OFFSET_IPV6] |= 0xB0;
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("fail\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v6;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR | IPA_FLT_TC;
+		rt_rule_entry->rule.attrib.u.v6.tc = 0xAA;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0]      = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3]      = 0X000000FF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR | IPA_FLT_TC;
+		rt_rule_entry->rule.attrib.u.v6.tc = 0xBB;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0]      = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3]      = 0X000000AA;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test9: IPv6 - Tests routing by destination address */
+/*---------------------------------------------------------------------------*/
+class IpaRoutingBlockTest009 : public IpaRoutingBlockTestFixture
+{
+public:
+	IpaRoutingBlockTest009()
+	{
+		m_name = "IpaRoutingBlockTest009";
+		m_description = " \
+		Routing block test 009 - IPv6 Exact Flow Label Match \
+		1. Generate and commit a single routing tables. \
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All Flow Label == 0xABCDE traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All Flow Label == 0x12345 traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v6;
+		Register(*this);
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[FLOW_CLASS_MSB_OFFSET_IPV6] &= 0xF0;
+		m_sendBuffer[FLOW_CLASS_MSB_OFFSET_IPV6] |= 0x0A;
+		m_sendBuffer[FLOW_CLASS_MB_OFFSET_IPV6] = 0xBC;
+		m_sendBuffer[FLOW_CLASS_LSB_OFFSET_IPV6] = 0xDE;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[FLOW_CLASS_MSB_OFFSET_IPV6] &= 0xF0;
+		m_sendBuffer2[FLOW_CLASS_MSB_OFFSET_IPV6] |= 0x01;
+		m_sendBuffer2[FLOW_CLASS_MB_OFFSET_IPV6] = 0x23;
+		m_sendBuffer2[FLOW_CLASS_LSB_OFFSET_IPV6] = 0x45;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("fail\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v6;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_FLOW_LABEL;
+		rt_rule_entry->rule.attrib.u.v6.flow_label = 0xABCDE;
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+//		rt_rule_entry->rule.hdr_hdl = hdr_entry->hdr_hdl; // gidons, there is no support for header insertion / removal yet.
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_FLOW_LABEL;
+		rt_rule_entry->rule.attrib.u.v6.flow_label = 0x12345;
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test10: IPv4 - Tests routing hashable vs non hashable priorities			*/
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest010 : public IpaRoutingBlockTestFixture
+{
+public:
+
+	IpaRoutingBlockTest010()
+	{
+		m_name = "IpaRoutingBlockTest10";
+		m_description =" \
+		Routing block test 010 - Destination address exact match non hashable priority higher than hashable \
+		both match the packet but only non hashable should hit\
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP == (192.168.2.170 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All DST_IP == (192.168.2.170 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v4;
+		m_minIPAHwType = IPA_HW_v3_0;
+		Register(*this);
+	}
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("fail\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v4;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AA; //192.168.02.170
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AA; //192.168.02.170
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 1; // hashable
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer2.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		/* Compare results */
+		isSuccess &= CompareResultVsGolden(m_sendBuffer,  m_sendSize,  rxBuff1, receivedSize);
+		isSuccess &= CompareResultVsGolden(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+		isSuccess &= CompareResultVsGolden(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize, sentBufferSize, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize, sentBufferSize, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize, sentBufferSize, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test11: IPv4 - Tests routing hashable vs non hashable priorities			*/
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest011 : public IpaRoutingBlockTestFixture
+{
+public:
+
+	IpaRoutingBlockTest011()
+	{
+		m_name = "IpaRoutingBlockTest011";
+		m_description =" \
+		Routing block test 011 - Destination address exact match hashable priority higher than non hashable \
+		both match the packet but only hashable should hit, second packet should get cache hit\
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP == (192.168.2.170 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All DST_IP == (192.168.2.170 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v4;
+		m_minIPAHwType = IPA_HW_v3_0;
+		Register(*this);
+	}
+
+	bool Setup()
+	{
+		return IpaRoutingBlockTestFixture:: Setup(true);
+	}
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("fail\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v4;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AA; //192.168.02.170
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 1; // hashable
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AA; //192.168.02.170
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer2.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		/* Compare results */
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer,  m_sendSize,  rxBuff1, receivedSize);
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize, receivedSize, rxBuff1) : IsCacheMiss(m_sendSize,receivedSize,rxBuff1);
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ? 
+			IsCacheHit_v5_0(m_sendSize2, receivedSize2, rxBuff2) : IsCacheHit(m_sendSize2,receivedSize2,rxBuff2);
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize3, receivedSize3, rxBuff3) : IsCacheMiss(m_sendSize3,receivedSize3,rxBuff3);
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize, sentBufferSize, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize, sentBufferSize, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize, sentBufferSize, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test12: IPv4 - Tests routing hashable vs non hashable priorities			*/
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest012 : public IpaRoutingBlockTestFixture
+{
+public:
+
+	IpaRoutingBlockTest012()
+	{
+		m_name = "IpaRoutingBlockTest012";
+		m_description =" \
+		Routing block test 012 - Destination address exact match hashable priority lower than non hashable \
+		no match on non hashable rule (with higher priority), match on hashable rule. two packets with\
+		different tuple are sent (but match the rule) cache miss expected\
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP == (192.168.2.170 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All DST_IP == (192.168.2.171 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v4;
+		m_minIPAHwType = IPA_HW_v3_0;
+		Register(*this);
+	}
+
+	bool Setup()
+	{
+		return IpaRoutingBlockTestFixture:: Setup(true);
+	}
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("fail\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v4;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AB; //192.168.02.171
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AA; //192.168.02.170
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 1; // hashable
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+		unsigned short port;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		port = ntohs(547);//DHCP Client Port
+		memcpy (&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		port = ntohs(546);//DHCP Client Port
+		memcpy (&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer2.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer2.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer2.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer2.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		/* Compare results */
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer,  m_sendSize,  rxBuff1, receivedSize);
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize, receivedSize, rxBuff1) : IsCacheMiss(m_sendSize,receivedSize,rxBuff1);
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize2, receivedSize2, rxBuff2) : IsCacheMiss(m_sendSize2,receivedSize2,rxBuff2);
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize3, receivedSize3, rxBuff3) : IsCacheMiss(m_sendSize3,receivedSize3,rxBuff3);
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize, sentBufferSize, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize, sentBufferSize, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize, sentBufferSize, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test13: IPv4 - Tests routing hashable vs non hashable priorities			*/
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest013 : public IpaRoutingBlockTestFixture
+{
+public:
+
+	IpaRoutingBlockTest013()
+	{
+		m_name = "IpaRoutingBlockTest013";
+		m_description =" \
+		Routing block test 013 - Destination address exact match \
+		no match on non hashable rule (with lower priority), match on hashable rule. two packets with\
+		different tuple are sent (but match the rule) cache miss expected\
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP == (192.168.2.170 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All DST_IP == (192.168.2.171 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v4;
+		m_minIPAHwType = IPA_HW_v3_0;
+		Register(*this);
+	}
+
+	bool Setup()
+	{
+		return IpaRoutingBlockTestFixture:: Setup(true);
+	}
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("fail\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v4;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AA; //192.168.02.170
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 1; // hashable
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AB; //192.168.02.171
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+		unsigned short port;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		port = ntohs(547);//DHCP Client Port
+		memcpy (&m_sendBuffer[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		port = ntohs(546);//DHCP Client Port
+		memcpy (&m_sendBuffer2[IPV4_DST_PORT_OFFSET], &port, sizeof(port));
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		/* Compare results */
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer,  m_sendSize,  rxBuff1, receivedSize);
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize, receivedSize, rxBuff1) : IsCacheMiss(m_sendSize,receivedSize,rxBuff1);
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize2, receivedSize2, rxBuff2) : IsCacheMiss(m_sendSize2,receivedSize2,rxBuff2);
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize3, receivedSize3, rxBuff3) : IsCacheMiss(m_sendSize3,receivedSize3,rxBuff3);
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize, sentBufferSize, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize, sentBufferSize, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize, sentBufferSize, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test14: IPv4 - Tests routing hashable vs non hashable priorities			*/
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest014 : public IpaRoutingBlockTestFixture
+{
+public:
+
+	IpaRoutingBlockTest014()
+	{
+		m_name = "IpaRoutingBlockTest014";
+		m_description =" \
+		Routing block test 014 - Destination address exact match \
+		no match on non hashable rule(with higher priority) , match on hashable rule. two identical\
+		packets are sent cache hit expected on the second one\
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP == (192.168.2.171 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All DST_IP == (192.168.2.170 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v4;
+		m_minIPAHwType = IPA_HW_v3_0;
+		Register(*this);
+	}
+
+	bool Setup()
+	{
+		return IpaRoutingBlockTestFixture:: Setup(true);
+	}
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("Failed memory allocation for rt_rule\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v4;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AB; //192.168.02.171
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AA; //192.168.02.170
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 1; // hashable
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			free(rt_rule);
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer2.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer2.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer2.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer2.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		/* Compare results */
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer,  m_sendSize,  rxBuff1, receivedSize);
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize, receivedSize, rxBuff1) : IsCacheMiss(m_sendSize,receivedSize,rxBuff1);
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ? 
+			IsCacheHit_v5_0(m_sendSize2, receivedSize2, rxBuff2) : IsCacheHit(m_sendSize2,receivedSize2,rxBuff2);
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize3, receivedSize3, rxBuff3) : IsCacheMiss(m_sendSize3,receivedSize3,rxBuff3);
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize, sentBufferSize, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize, sentBufferSize, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize, sentBufferSize, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+};
+
+
+/*--------------------------------------------------------------------------*/
+/* Test15: IPv4 - Tests routing hashable vs non hashable priorities			*/
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest015 : public IpaRoutingBlockTestFixture
+{
+public:
+
+	IpaRoutingBlockTest015()
+	{
+		m_name = "IpaRoutingBlockTest015";
+		m_description =" \
+		Routing block test 015 - Destination address exact match \
+		no match on non hashable rule(with lower priority) , match on hashable rule. two identical\
+		packets are sent cache hit expected on the second one\
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP == (192.168.2.170 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All DST_IP == (192.168.2.171 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v4;
+		m_minIPAHwType = IPA_HW_v3_0;
+		Register(*this);
+	}
+
+	bool Setup()
+	{
+		return IpaRoutingBlockTestFixture:: Setup(true);
+	}
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("Failed memory allocation for rt_rule\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v4;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AA; //192.168.02.170
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 1; // hashable
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AB; //192.168.02.171
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		for (int i = 0; i < rt_rule->num_rules; i++) {
+			uRtRuleHdl[i] = rt_rule->rules[i].rt_rule_hdl;
+		}
+		uNumRtRules = rt_rule->num_rules;
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+
+	bool RemoveLastRule(enum ipa_ip_type ipType)
+	{
+		struct ipa_ioc_del_rt_rule *ruleTable;
+
+		ruleTable = (struct ipa_ioc_del_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_del_rt_rule) +
+				   sizeof(struct ipa_rt_rule_del));
+
+		ruleTable->commit = 1;
+		ruleTable->ip = ipType;
+		ruleTable->num_hdls = 1;
+		ruleTable->hdl[0].hdl = uRtRuleHdl[uNumRtRules - 1];
+		ruleTable->hdl[0].status = 0;
+
+		if (false == m_routing.DeleteRoutingRule(ruleTable))
+		{
+			printf("Routing rule deletion failed!\n");
+			return false;
+		}
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		/* Compare results */
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer,  m_sendSize,  rxBuff1, receivedSize);
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize, receivedSize, rxBuff1) : IsCacheMiss(m_sendSize,receivedSize,rxBuff1);
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ? 
+			IsCacheHit_v5_0(m_sendSize2, receivedSize2, rxBuff2) : IsCacheHit(m_sendSize2,receivedSize2,rxBuff2);
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize3, receivedSize3, rxBuff3) : IsCacheMiss(m_sendSize3,receivedSize3,rxBuff3);
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize, sentBufferSize, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize, sentBufferSize, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize, sentBufferSize, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+
+	bool ReceivePacketsAndCompareSpecial()
+	{
+		size_t receivedSize = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+
+		if (NULL == rxBuff1)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		/* Compare results */
+		isSuccess &= CompareResultVsGolden_w_Status(m_sendBuffer,  m_sendSize,  rxBuff1, receivedSize);
+
+		isSuccess &= (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) ?
+			IsCacheMiss_v5_0(m_sendSize, receivedSize, rxBuff1) : IsCacheMiss(m_sendSize,receivedSize,rxBuff1);
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+		size_t j;
+		for(j = 0; j < m_sendSize; j++)
+		    snprintf(&sentBuffer[3 * j], sentBufferSize - 3 * j,
+				" %02X", m_sendBuffer[j]);
+		for(j = 0; j < receivedSize; j++)
+		    snprintf(&recievedBuffer[3 * j], recievedBufferSize - 3 * j,
+				" %02X", rxBuff1[j]);
+		printf("Expected Value1 (%zu)\n%s\n, Received Value1(%zu)\n%s\n",m_sendSize,sentBuffer,receivedSize,recievedBuffer);
+
+		delete[] rxBuff1;
+
+		return isSuccess;
+	}
+
+protected:
+	uint32_t uRtRuleHdl[3];
+	uint8_t uNumRtRules;
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test16: IPv4 - Tests routing hashable vs non hashable priorities			*/
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest016 : public IpaRoutingBlockTestFixture
+{
+public:
+
+	IpaRoutingBlockTest016()
+	{
+		m_name = "IpaRoutingBlockTest016";
+		m_description =" \
+		Routing block test 016 - Destination address exact match max priority for non hashable \
+		match on both rule, non hashable rule should win because max priority\
+		packets are sent. No cache hit is expected\
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP == (192.168.2.170 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All DST_IP == (192.168.2.170 & 255.255.255.255)traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v4;
+		m_minIPAHwType = IPA_HW_v3_0;
+		Register(*this);
+	}
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("Failed memory allocation for rt_rule\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v4;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AA; //192.168.02.170
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 1; // hashable
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802AA; //192.168.02.170
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+		rt_rule_entry->rule.max_prio =  1; // max priority
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool ReceivePacketsAndCompare()
+	{
+		size_t receivedSize = 0;
+		size_t receivedSize2 = 0;
+		size_t receivedSize3 = 0;
+		bool isSuccess = true;
+
+		// Receive results
+		Byte *rxBuff1 = new Byte[0x400];
+		Byte *rxBuff2 = new Byte[0x400];
+		Byte *rxBuff3 = new Byte[0x400];
+
+		if (NULL == rxBuff1 || NULL == rxBuff2 || NULL == rxBuff3)
+		{
+			printf("Memory allocation error.\n");
+			return false;
+		}
+
+		receivedSize = m_consumer2.ReceiveData(rxBuff1, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize2 = m_consumer2.ReceiveData(rxBuff2, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize2, m_consumer.m_fromChannelName.c_str());
+
+		receivedSize3 = m_defaultConsumer.ReceiveData(rxBuff3, 0x400);
+		printf("Received %zu bytes on %s.\n", receivedSize3, m_defaultConsumer.m_fromChannelName.c_str());
+
+		/* Compare results */
+		isSuccess &= CompareResultVsGolden(m_sendBuffer,  m_sendSize,  rxBuff1, receivedSize);
+		isSuccess &= CompareResultVsGolden(m_sendBuffer2, m_sendSize2, rxBuff2, receivedSize2);
+		isSuccess &= CompareResultVsGolden(m_sendBuffer3, m_sendSize3, rxBuff3, receivedSize3);
+
+		size_t recievedBufferSize = receivedSize * 3;
+		size_t sentBufferSize = m_sendSize * 3;
+		char *recievedBuffer = new char[recievedBufferSize];
+		char *sentBuffer = new char[sentBufferSize];
+
+		memset(recievedBuffer, 0, recievedBufferSize);
+		memset(sentBuffer, 0, sentBufferSize);
+
+		print_packets(receivedSize, m_sendSize, recievedBufferSize, sentBufferSize, rxBuff1, m_sendBuffer, recievedBuffer, sentBuffer);
+		print_packets(receivedSize2, m_sendSize2, recievedBufferSize, sentBufferSize, rxBuff2, m_sendBuffer2, recievedBuffer, sentBuffer);
+		print_packets(receivedSize3, m_sendSize3, recievedBufferSize, sentBufferSize, rxBuff3, m_sendBuffer3, recievedBuffer, sentBuffer);
+
+		delete[] recievedBuffer;
+		delete[] sentBuffer;
+
+		delete[] rxBuff1;
+		delete[] rxBuff2;
+		delete[] rxBuff3;
+
+		return isSuccess;
+	}
+
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test17: IPv4 - Tests routing hashable, non hashable,                     */
+/* cache/hash invalidation test on rule addition                            */
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest017 : public IpaRoutingBlockTest015
+{
+public:
+
+	IpaRoutingBlockTest017()
+	{
+		m_name = "IpaRoutingBlockTest017";
+		m_description =" \
+		Routing block test 017 - this test perform test 015 and then commits another rule\
+		another identical packet is sent: DST_IP == 192.168.02.170 and expected to get cache miss";
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+		if (false == isSuccess)
+		{
+			printf("ReceivePacketsAndCompare failure.\n");
+			return false;
+		}
+
+		// until here test 15 was run, now we test hash invalidation
+
+		// commit the rules again to clear the cache
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// send the packet again
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// validate we got cache miss
+		isSuccess = ReceivePacketsAndCompareSpecial();
+		if (false == isSuccess)
+		{
+			printf("ReceivePacketsAndCompareSpecial failure.\n");
+		}
+		return isSuccess;
+	} // Run()
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test18: IPv4 - Tests routing hashable, non hashable,                     */
+/* cache/hash invalidation test on rule delition                            */
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest018 : public IpaRoutingBlockTest015
+{
+public:
+
+	IpaRoutingBlockTest018()
+	{
+		m_name = "IpaRoutingBlockTest018";
+		m_description =" \
+		Routing block test 018 - this test perform test 015 and then removes last rule\
+		another identical packet is sent: DST_IP == 192.168.02.170 and expected to get cache miss";
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV4] = 0xAA;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+		if (false == isSuccess)
+		{
+			printf("ReceivePacketsAndCompare failure.\n");
+			return false;
+		}
+
+		// until here test 15 was run, now we test hash invalidation
+
+		// delete the last rule, this should clear the cache
+		res = RemoveLastRule(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed removing filtering rules.\n");
+			return false;
+		}
+
+		// send the packet again
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// validate we got cache miss
+		isSuccess = ReceivePacketsAndCompareSpecial();
+		if (false == isSuccess)
+		{
+			printf("ReceivePacketsAndCompareSpecial failure.\n");
+		}
+		return isSuccess;
+	} // Run()
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test20: IPv6 - Tests routing hashable vs non hashable priorities	    */
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest020 : public IpaRoutingBlockTest010
+{
+public:
+
+	IpaRoutingBlockTest020()
+	{
+		m_name = "IpaRoutingBlockTest20";
+		m_description =" \
+		Routing block test 020 - Destination address exact match non hashable priority higher than hashable \
+		both match the packet but only non hashable should hit\
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000FF \
+			traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000FF \
+			traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v6;
+		m_minIPAHwType = IPA_HW_v3_0;
+	}
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("Failed memory allocation for rt_rule\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v6;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0]      = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3]      = 0X000000FF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0]      = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3]      = 0X000000FF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 1; // hashable
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			free(rt_rule);
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+};
+
+
+/*--------------------------------------------------------------------------*/
+/* Test21: IPv6 - Tests routing hashable vs non hashable priorities	    */
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest021 : public IpaRoutingBlockTest011
+{
+public:
+
+	IpaRoutingBlockTest021()
+	{
+		m_name = "IpaRoutingBlockTest021";
+		m_description =" \
+		Routing block test 021 - Destination address exact match hashable priority higher than non hashable \
+		both match the packet but only hashable should hit, second packet should get cache hit\
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000FF  - hashable\
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000FF - non hahsable \
+			traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v6;
+		m_minIPAHwType = IPA_HW_v3_0;
+	}
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("Failed memory allocation for rt_rule\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v6;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0]      = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3]      = 0X000000FF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 1; // hashable
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0]      = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3]      = 0X000000FF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			free(rt_rule);
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test22: IPv6 - Tests routing hashable vs non hashable priorities         */
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest022 : public IpaRoutingBlockTest012
+{
+public:
+
+	IpaRoutingBlockTest022()
+	{
+		m_name = "IpaRoutingBlockTest022";
+		m_description =" \
+		Routing block test 022 - Destination address exact match hashable priority higher than non hashable \
+		no match on non hashable rule (with higher priority), match on hashable rule. two packets with\
+		different tuple are sent (but match the rule) cache miss expected\
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000AA  - non hashable\
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000FF -  hahsable \
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v6;
+		m_minIPAHwType = IPA_HW_v3_0;
+	}
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("Failed memory allocation for rt_rule\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v6;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0]      = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3]      = 0X000000AA;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0]      = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3]      = 0X000000FF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 1; // hashable
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			free(rt_rule);
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+		unsigned short port;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		port = ntohs(546);//DHCP Client Port
+		memcpy (&m_sendBuffer[IPV6_DST_PORT_OFFSET], &port, sizeof(port));
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		port = ntohs(547);//DHCP Client Port
+		memcpy (&m_sendBuffer2[IPV6_DST_PORT_OFFSET], &port, sizeof(port));
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test23: IPv6 - Tests routing hashable vs non hashable priorities	    */
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest023 : public IpaRoutingBlockTest013
+{
+public:
+
+	IpaRoutingBlockTest023()
+	{
+		m_name = "IpaRoutingBlockTest023";
+		m_description =" \
+		Routing block test 023 - Destination address exact match \
+		no match on non hashable rule (with lower priority), match on hashable rule. two packets with\
+		different tuple are sent (but match the rule) cache miss expected\
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000FF  - hashable\
+			traffic goes to pipe IPA_CLIENT_TEST2_CONS\
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000AA -  non hahsable \
+			traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v6;
+		m_minIPAHwType = IPA_HW_v3_0;
+	}
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+				   NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("Failed memory allocation for rt_rule\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v6;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] 	 = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] 	 = 0X000000FF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 1; // hashable
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] 	 = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] 	 = 0X000000AA;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			free(rt_rule);
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+		unsigned short port;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		port = ntohs(546);//DHCP Client Port
+		memcpy (&m_sendBuffer[IPV6_DST_PORT_OFFSET], &port, sizeof(port));
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		port = ntohs(547);//DHCP Client Port
+		memcpy (&m_sendBuffer2[IPV6_DST_PORT_OFFSET], &port, sizeof(port));
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test24: IPv6 - Tests routing hashable vs non hashable priorities	    */
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest024 : public IpaRoutingBlockTest014
+{
+public:
+
+	IpaRoutingBlockTest024()
+	{
+		m_name = "IpaRoutingBlockTest024";
+		m_description =" \
+		Routing block test 024 - Destination address exact match \
+		no match on non hashable rule(with higher priority) , match on hashable rule. two identical\
+		packets are sent cache hit expected on the second one\
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000AA  - non hashable\
+			traffic goes to pipe IPA_CLIENT_TEST2_CONS\
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000FF -  hahsable \
+			traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v6;
+		m_minIPAHwType = IPA_HW_v3_0;
+	}
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+				   NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("Failed memory allocation for rt_rule\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v6;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] 	 = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] 	 = 0X000000AA;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] 	 = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] 	 = 0X000000FF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 1; // hashable
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			free(rt_rule);
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test25: IPv6 - Tests routing hashable vs non hashable priorities	    */
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest025 : public IpaRoutingBlockTest015
+{
+public:
+	IpaRoutingBlockTest025()
+	{
+		m_name = "IpaRoutingBlockTest025";
+		m_description =" \
+		Routing block test 025 - Destination address exact match \
+		no match on non hashable rule(with lower priority) , match on hashable rule. two identical\
+		packets are sent cache hit expected on the second one\
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000FF  - hashable\
+			traffic goes to pipe IPA_CLIENT_TEST2_CONS\
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000AA -  non hahsable \
+			traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v6;
+		m_minIPAHwType = IPA_HW_v3_0;
+	}
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+				   NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("Failed memory allocation for rt_rule\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v6;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] 	 = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] 	 = 0X000000FF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 1; // hashable
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] 	 = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] 	 = 0X000000AA;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			free(rt_rule);
+			return false;
+		}
+
+		for (int i = 0; i < rt_rule->num_rules; i++) {
+			uRtRuleHdl[i] = rt_rule->rules[i].rt_rule_hdl;
+		}
+		uNumRtRules = rt_rule->num_rules;
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+};
+
+
+/*--------------------------------------------------------------------------*/
+/* Test26: IPv6 - Tests routing hashable vs non hashable priorities	    */
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest026 : public IpaRoutingBlockTest016
+{
+public:
+
+	IpaRoutingBlockTest026()
+	{
+		m_name = "IpaRoutingBlockTest026";
+		m_description =" \
+		Routing block test 026 - Destination address exact match max priority for non hashable \
+		match on both rule, non hashable rule should win because max priority\
+		packets are sent cache hit expected on the second one\
+		2. Generate and commit Three routing rules: (DST & Mask Match). \
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000FF  - hashable\
+			traffic goes to pipe IPA_CLIENT_TEST2_CONS\
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000FF -  non hahsable max prio \
+			traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v6;
+		m_minIPAHwType = IPA_HW_v3_0;
+	}
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+				   NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("Failed memory allocation for rt_rule\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v6;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] 	 = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] 	 = 0X000000FF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 1; // hashable
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] 	 = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] 	 = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] 	 = 0X000000FF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+		rt_rule_entry->rule.max_prio = 1; // max prio
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+		rt_rule_entry->rule.hashable = 0; // non hashable
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			free(rt_rule);
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test27: IPv6 - Tests routing hashable, non hashable,                     */
+/* cache/hash invalidation test on rule addition                            */
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest027 : public IpaRoutingBlockTest025
+{
+public:
+
+	IpaRoutingBlockTest027()
+	{
+		m_name = "IpaRoutingBlockTest027";
+		m_description =" \
+		Routing block test 027 - this test perform test 025 and then commits another rule\
+		another identical packet is sent: DST_IP == 192.168.02.170 and expected to get cache miss";
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+		if (false == isSuccess)
+		{
+			printf("ReceivePacketsAndCompare failure.\n");
+			return false;
+		}
+
+		// until here test 25 was run, now we test hash invalidation
+
+		// commit the rules again to clear the cache
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// send the packet again
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// validate we got cache miss
+		isSuccess = ReceivePacketsAndCompareSpecial();
+		if (false == isSuccess)
+		{
+			printf("ReceivePacketsAndCompareSpecial failure.\n");
+		}
+		return isSuccess;
+	} // Run()
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test28: IPv6 - Tests routing hashable, non hashable,                     */
+/* cache/hash invalidation test on rule delition                            */
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest028 : public IpaRoutingBlockTest025
+{
+public:
+
+	IpaRoutingBlockTest028()
+	{
+		m_name = "IpaRoutingBlockTest028";
+		m_description =" \
+		Routing block test 028 - this test perform test 025 and then deletes last rule\
+		another identical packet is sent: DST_IP == 192.168.02.170 and expected to get cache miss";
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xFF;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+		if (false == isSuccess)
+		{
+			printf("ReceivePacketsAndCompare failure.\n");
+			return false;
+		}
+
+		// until here test 25 was run, now we test hash invalidation
+
+		// delete the last rule, this should clear the cache
+		res = RemoveLastRule(IPA_IP_v6);
+		if (false == res) {
+			printf("Failed removing filtering rules.\n");
+			return false;
+		}
+
+		// send the packet again
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// validate we got cache miss
+		isSuccess = ReceivePacketsAndCompareSpecial();
+		if (false == isSuccess)
+		{
+			printf("ReceivePacketsAndCompareSpecial failure.\n");
+		}
+		return isSuccess;
+	} // Run()
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test30: Pure ack packet matching											*/
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest030 : IpaRoutingBlockTestFixture
+{
+public:
+	IpaRoutingBlockTest030()
+	{
+		m_name = "IpaRoutingBlockTest030";
+		m_description =" \
+		Routing block test 030 - Pure Ack packet matching \
+		1. Generate and commit a single routing table. \
+		2. Generate and commit Three routing rules: \
+			All TCP pure ack traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All DST_IP == (192.168.2.200 & 255.255.255.255) traffic goes to pipe IPA_CLIENT_TEST3_CONS\
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v4;
+		m_minIPAHwType = IPA_HW_v4_5;
+		Register(*this);
+	}
+
+	bool LoadPackets()
+	{
+		if (!LoadNoPayloadPacket(m_IpaIPType, m_sendBuffer, m_sendSize)) {
+			LOG_MSG_ERROR("Failed loading No Payload Packet");
+			return false;
+		}
+
+		if (!LoadDefaultPacket(m_IpaIPType, m_sendBuffer2, m_sendSize2)) {
+			LOG_MSG_ERROR("Failed loading default Packet");
+			return false;
+		}
+
+		if (!LoadDefaultPacket(m_IpaIPType, m_sendBuffer3, m_sendSize3)) {
+			LOG_MSG_ERROR("Failed loading default Packet");
+			return false;
+		}
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load IP packets
+		res = LoadPackets();
+		if (false == res) {
+			printf("Failed loading packets\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[IPv4_TCP_FLAGS_OFFSET] |= TCP_ACK_FLAG_MASK;
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0xC8;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[IPv4_TCP_FLAGS_OFFSET] |= TCP_ACK_FLAG_MASK;
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV4] = 0xC8;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize2);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		m_sendBuffer3[IPv4_TCP_FLAGS_OFFSET] |= TCP_ACK_FLAG_MASK;
+		m_sendBuffer3[DST_ADDR_LSB_OFFSET_IPV4] = 0x64;
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("fail\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v4;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_IS_PURE_ACK;
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0xC0A802C8;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+};
+
+/*--------------------------------------------------------------------------*/
+/* Test31: IPv6 Pure ack packet matching		 							*/
+/*--------------------------------------------------------------------------*/
+class IpaRoutingBlockTest031 : public IpaRoutingBlockTestFixture
+{
+public:
+	IpaRoutingBlockTest031()
+	{
+		m_name = "IpaRoutingBlockTest031";
+		m_description =" \
+		Routing block test 031 - IPv6 Pure Ack packet matching \
+		1. Generate and commit a single routing table. \
+		2. Generate and commit Three routing rules: \
+			All TCP pure ack traffic goes to pipe IPA_CLIENT_TEST2_CONS \
+			All DST_IP ==	0XFF020000 \
+							0x00000000 \
+							0x00000000 \
+							0X000000F5 \
+			traffic goes to pipe IPA_CLIENT_TEST3_CONS \
+			All other traffic goes to pipe IPA_CLIENT_TEST4_CONS";
+		m_IpaIPType = IPA_IP_v6;
+		m_minIPAHwType = IPA_HW_v4_5;
+		Register(*this);
+	}
+
+	bool LoadPackets()
+	{
+		if (!LoadNoPayloadPacket(m_IpaIPType, m_sendBuffer, m_sendSize)) {
+			LOG_MSG_ERROR("Failed loading No Payload Packet");
+			return false;
+		}
+
+		if (!LoadNoPayloadPacket(m_IpaIPType, m_sendBuffer2, m_sendSize2)) {
+			LOG_MSG_ERROR("Failed loading default Packet");
+			return false;
+		}
+
+		if (!LoadNoPayloadPacket(m_IpaIPType, m_sendBuffer3, m_sendSize3)) {
+			LOG_MSG_ERROR("Failed loading default Packet");
+			return false;
+		}
+
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		// Add the relevant routing rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding routing rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet)
+		res = LoadPackets();
+		if (false == res) {
+			printf("Failed loading packets\n");
+			return false;
+		}
+
+		// Send first packet
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV6] = 0xF5;
+		m_sendBuffer[IPv6_TCP_FLAGS_OFFSET] |= TCP_ACK_FLAG_MASK;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send second packet
+		m_sendBuffer2[DST_ADDR_LSB_OFFSET_IPV6] = 0xF5;
+		isSuccess = m_producer.SendData(m_sendBuffer2, m_sendSize);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Send third packet
+		isSuccess = m_producer.SendData(m_sendBuffer3, m_sendSize3);
+		if (false == isSuccess)
+		{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// Receive packets from the channels and compare results
+		isSuccess = ReceivePacketsAndCompare();
+
+		return isSuccess;
+	} // Run()
+
+	bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+		const int NUM_RULES = 3;
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       NUM_RULES*sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("fail\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = NUM_RULES;
+		rt_rule->ip = IPA_IP_v6;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 0;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_IS_PURE_ACK;
+
+		rt_rule_entry = &rt_rule->rules[1];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST3_CONS;
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0]      = 0XFF020000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2]      = 0x00000000;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3]      = 0X000000F5;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+
+		rt_rule_entry = &rt_rule->rules[2];
+		rt_rule_entry->at_rear = 1;
+		rt_rule_entry->rule.dst = IPA_CLIENT_TEST4_CONS;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		return true;
+	}
+};
+
+/*---------------------------------------------------------------------------*/
+/* Test100: Cache LRU behavior test  */
+/*---------------------------------------------------------------------------*/
+#define CHACHE_ENTRIES 64
+#define CHACHE_PLUS_ONE (CHACHE_ENTRIES +1)
+class IpaRoutingBlockTest040 : public IpaRoutingBlockTestFixture
+{
+public:
+	IpaRoutingBlockTest040()
+	{
+		m_name = "IpaRoutingBlockTest040";
+		m_description = " \
+		Routing block test 40 - Cache LRU behavior test \
+		1. Preload the cache by sending 64 packets for different connections \
+		2. Send another packet for 65th connection \
+		3. Send packets for first 64 connections \
+		4. Verify that 1st connection’s entry was reclaimed";
+		m_IpaIPType = IPA_IP_v4;
+		m_minIPAHwType = IPA_HW_v4_0;
+		Register(*this);
+	}
+
+	bool Setup()
+	{
+		return IpaRoutingBlockTestFixture:: Setup(true);
+	}
+
+	virtual bool AddRules()
+	{
+		struct ipa_ioc_add_rt_rule *rt_rule;
+		struct ipa_rt_rule_add *rt_rule_entry;
+
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+			       CHACHE_PLUS_ONE * sizeof(struct ipa_rt_rule_add));
+
+		if(!rt_rule) {
+			printf("Failed memory allocation for rt_rule\n");
+			return false;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = CHACHE_PLUS_ONE;
+		rt_rule->ip = IPA_IP_v4;
+		strlcpy(rt_rule->rt_tbl_name, "LAN", sizeof(rt_rule->rt_tbl_name));
+
+		for (int i = 0; i < CHACHE_PLUS_ONE; i++) {
+			rt_rule_entry = &rt_rule->rules[i];
+			rt_rule_entry->at_rear = 1;
+			rt_rule_entry->rule.dst = IPA_CLIENT_TEST2_CONS;
+			rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+			rt_rule_entry->rule.attrib.u.v4.dst_addr = 0xC0A80101 + i; // DST_IP == 192.168.1.(1+i)
+			rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+			rt_rule_entry->rule.hashable = 1;
+		}
+
+		// The last rule has to be catch all, otherwize no rule will work
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0x0;
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			printf("Routing rule addition failed!\n");
+			return false;
+		}
+
+		printf("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+
+		free(rt_rule);
+
+		InitFilteringBlock();
+
+		printf("Leaving %s, %s()\n",__FUNCTION__, __FILE__);
+		return true;
+	}
+
+	bool Run()
+	{
+		bool res = false;
+		bool isSuccess = false;
+
+		printf("Entering %s, %s()\n", __FUNCTION__, __FILE__);
+
+		// Add the relevant filtering rules
+		res = AddRules();
+		if (false == res) {
+			printf("Failed adding filtering rules.\n");
+			return false;
+		}
+
+		// Load input data (IP packet) from file
+		res = LoadFiles(IPA_IP_v4);
+		if (false == res) {
+			printf("Failed loading files.\n");
+			return false;
+		}
+
+		// Send the first CHACHE_ENTRIES packets
+		// Receive packets from the channels and compare results
+		// All rules should be cache miss
+		for (int i = 0; i < CHACHE_ENTRIES; i++) {
+			m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0x1 + i;
+			isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+			if (false == isSuccess)
+			{
+				printf("SendData failure.\n");
+				return false;
+			}
+
+			isSuccess = ReceivePacketAndCompareFrom(m_consumer, m_sendBuffer, m_sendSize, false);
+			if (false == isSuccess)	{
+				printf("%s:%d: ReceivePacketAndCompareFrom failure.\n", __FUNCTION__, __LINE__);
+				return false;
+			}
+		}
+
+		// Send again the first CHACHE_ENTRIES packets
+		// Receive packets from the channels and compare results
+		// All rules should be cache hit
+		for (int i = 0; i < CHACHE_ENTRIES; i++) {
+			m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0x1 + i;
+			isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+			if (false == isSuccess)
+			{
+				printf("SendData failure.\n");
+				return false;
+			}
+
+			isSuccess = ReceivePacketAndCompareFrom(m_consumer, m_sendBuffer, m_sendSize, true);
+			if (false == isSuccess)	{
+				printf("%s:%d: ReceivePacketAndCompareFrom failure.\n", __FUNCTION__, __LINE__);
+				return false;
+			}
+		}
+
+		// Send a packet to a new filter entry, this should trigger the LRU clear
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0x1 + CHACHE_ENTRIES;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)	{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// receive and verify that cache was missed
+		isSuccess = ReceivePacketAndCompareFrom(m_consumer, m_sendBuffer, m_sendSize, false);
+		if (false == isSuccess)	{
+			printf("%s:%d: ReceivePacketAndCompareFrom failure.\n", __FUNCTION__, __LINE__);
+			return false;
+		}
+
+		// send the first packet again
+		m_sendBuffer[DST_ADDR_LSB_OFFSET_IPV4] = 0x1;
+		isSuccess = m_producer.SendData(m_sendBuffer, m_sendSize);
+		if (false == isSuccess)	{
+			printf("SendData failure.\n");
+			return false;
+		}
+
+		// receive and verify that cache was missed
+		isSuccess = ReceivePacketAndCompareFrom(m_consumer, m_sendBuffer, m_sendSize, false);
+		if (false == isSuccess)	{
+			printf("%s:%d: ReceivePacketAndCompareFrom failure.\n", __FUNCTION__, __LINE__);
+			return false;
+		}
+
+		printf("Leaving %s, %s(), Returning %d\n",__FUNCTION__, __FILE__, isSuccess);
+
+		return isSuccess;
+	} // Run()
+};
+
+static class IpaRoutingBlockTest1 ipaRoutingBlockTest1;
+static class IpaRoutingBlockTest2 ipaRoutingBlockTest2;
+static class IpaRoutingBlockTest3 ipaRoutingBlockTest3;
+static class IpaRoutingBlockTest4 ipaRoutingBlockTest4;
+static class IpaRoutingBlockTest5 ipaRoutingBlockTest5;
+static class IpaRoutingBlockTest006 ipaRoutingBlockTest006;
+static class IpaRoutingBlockTest007 ipaRoutingBlockTest007;
+static class IpaRoutingBlockTest008 ipaRoutingBlockTest008;
+static class IpaRoutingBlockTest009 ipaRoutingBlockTest009;
+
+static class IpaRoutingBlockTest010 ipaRoutingBlockTest010;
+static class IpaRoutingBlockTest011 ipaRoutingBlockTest011;
+static class IpaRoutingBlockTest012 ipaRoutingBlockTest012;
+static class IpaRoutingBlockTest013 ipaRoutingBlockTest013;
+static class IpaRoutingBlockTest014 ipaRoutingBlockTest014;
+static class IpaRoutingBlockTest015 ipaRoutingBlockTest015;
+static class IpaRoutingBlockTest016 ipaRoutingBlockTest016;
+static class IpaRoutingBlockTest017 ipaRoutingBlockTest017;
+static class IpaRoutingBlockTest018 ipaRoutingBlockTest018;
+
+static class IpaRoutingBlockTest020 ipaRoutingBlockTest020;
+static class IpaRoutingBlockTest021 ipaRoutingBlockTest021;
+static class IpaRoutingBlockTest022 ipaRoutingBlockTest022;
+static class IpaRoutingBlockTest023 ipaRoutingBlockTest023;
+static class IpaRoutingBlockTest024 ipaRoutingBlockTest024;
+static class IpaRoutingBlockTest025 ipaRoutingBlockTest025;
+static class IpaRoutingBlockTest026 ipaRoutingBlockTest026;
+static class IpaRoutingBlockTest027 ipaRoutingBlockTest027;
+static class IpaRoutingBlockTest028 ipaRoutingBlockTest028;
+
+static class IpaRoutingBlockTest030 ipaRoutingBlockTest030;
+static class IpaRoutingBlockTest031 ipaRoutingBlockTest031;
+
+static class IpaRoutingBlockTest040 ipaRoutingBlockTest040;
+
+

+ 94 - 0
kernel-tests/TLPAggregationTestFixture.cpp

@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "TLPAggregationTestFixture.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+
+//define the static Pipes which will be used by all derived tests.
+Pipe TLPAggregationTestFixture::m_IpaToUsbPipeNoAgg(IPA_CLIENT_TEST3_CONS,
+		IPA_TEST_CONFIGURATION_8);
+Pipe TLPAggregationTestFixture::m_IpaToUsbPipeAggr(IPA_CLIENT_TEST_CONS,
+		IPA_TEST_CONFIGURATION_8);
+Pipe TLPAggregationTestFixture::m_UsbNoAggToIpaPipeAgg(IPA_CLIENT_TEST3_PROD,
+		IPA_TEST_CONFIGURATION_8);
+Pipe TLPAggregationTestFixture::m_UsbDeaggToIpaPipeNoAgg(IPA_CLIENT_TEST_PROD,
+		IPA_TEST_CONFIGURATION_8);
+Pipe TLPAggregationTestFixture::m_UsbDeaggToIpaPipeAgg(IPA_CLIENT_TEST2_PROD,
+		IPA_TEST_CONFIGURATION_8);
+Pipe TLPAggregationTestFixture::m_IpaToUsbPipeAggTime(IPA_CLIENT_TEST2_CONS,
+		IPA_TEST_CONFIGURATION_8);
+Pipe TLPAggregationTestFixture::m_UsbNoAggToIpaPipeAggTime(IPA_CLIENT_TEST4_PROD,
+		IPA_TEST_CONFIGURATION_8);
+
+/////////////////////////////////////////////////////////////////////////////////
+
+TLPAggregationTestFixture::TLPAggregationTestFixture()
+{
+	m_testSuiteName.push_back("TLPAgg");
+	m_maxIPAHwType = IPA_HW_v2_6L;
+	Register(*this);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool TLPAggregationTestFixture::Setup()
+{
+	bool bRetVal = true;
+
+	//Set the configuration to support USB->IPA and IPA->USB pipes.
+	ConfigureScenario(8);
+
+	//Initialize the pipe for all the tests - this will open the inode which represents the pipe.
+	bRetVal &= m_IpaToUsbPipeNoAgg.Init();
+	bRetVal &= m_IpaToUsbPipeAggr.Init();
+	bRetVal &= m_UsbNoAggToIpaPipeAgg.Init();
+	bRetVal &= m_UsbDeaggToIpaPipeNoAgg.Init();
+	bRetVal &= m_UsbDeaggToIpaPipeAgg.Init();
+	bRetVal &= m_IpaToUsbPipeAggTime.Init();
+	bRetVal &= m_UsbNoAggToIpaPipeAggTime.Init();
+	return bRetVal;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+bool TLPAggregationTestFixture::Teardown()
+{
+	//The Destroy method will close the inode.
+	m_IpaToUsbPipeNoAgg.Destroy();
+	m_IpaToUsbPipeAggr.Destroy();
+	m_UsbNoAggToIpaPipeAgg.Destroy();
+	m_UsbDeaggToIpaPipeNoAgg.Destroy();
+	m_UsbDeaggToIpaPipeAgg.Destroy();
+	m_IpaToUsbPipeAggTime.Destroy();
+	m_UsbNoAggToIpaPipeAggTime.Destroy();
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////

+ 72 - 0
kernel-tests/TLPAggregationTestFixture.h

@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "Constants.h"
+#include "Logger.h"
+#include "linux/msm_ipa.h"
+#include "TestsUtils.h"
+#include "TestBase.h"
+#include "Pipe.h"
+
+/*This class will be the base class of all TLP Aggregation tests.
+ *Any method other than the test case itself can be declared in
+ *this Fixture thus allowing the derived classes to
+ *implement only the test case.
+ *All the test of the Aggregation uses one
+ *input and one output in DMA mode.
+ */
+class TLPAggregationTestFixture:public TestBase
+{
+public:
+	/*This Constructor will register each instance that it creates.*/
+	TLPAggregationTestFixture();
+
+	/*This method will create and initialize two Pipe object for the
+	 *USB (Ethernet) Pipes, one as input and the other as output.
+	 */
+	virtual bool Setup();
+
+	/*This method will destroy the pipes.*/
+	virtual bool Teardown();
+
+	/*The client type are set from the peripheral perspective*/
+	static Pipe m_IpaToUsbPipeNoAgg;
+	static Pipe m_IpaToUsbPipeAggr;
+	static Pipe m_UsbNoAggToIpaPipeAgg;
+	static Pipe m_UsbDeaggToIpaPipeNoAgg;
+	static Pipe m_UsbDeaggToIpaPipeAgg;
+	static Pipe m_IpaToUsbPipeAggTime;
+	static Pipe m_UsbNoAggToIpaPipeAggTime;
+};

+ 946 - 0
kernel-tests/TLPAggregationTests.cpp

@@ -0,0 +1,946 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "TLPAggregationTestFixture.h"
+#include "Constants.h"
+#include "TestsUtils.h"
+#include "linux/msm_ipa.h"
+
+#define NUM_PACKETS 5
+#define TIME_LIMIT_NUM_PACKETS 1
+#define MAX_PACKET_SIZE 1024
+#define AGGREGATION_LOOP 4
+
+int test_num = 0;
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class TLPAggregationTest: public TLPAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	TLPAggregationTest()
+	{
+		m_name = "TLPAggregationTest";
+		m_description = "TLP Aggregation test - sends 5 packets and receives 1 "
+				"aggregated packet";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool Run()
+	{
+		bool bTestResult = true;
+		//The packets that will be sent
+		Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+		//The real sizes of the packets that will be sent
+		int pPacketsSizes[NUM_PACKETS];
+		//Buffer for the packet that will be received
+		Byte pReceivedPacket[MAX_PACKET_SIZE];
+		//Total size of all sent packets (this is the max size of the aggregated packet
+		//minus 2 bytes for each packet in the aggregated packet)
+		int nTotalPacketsSize = MAX_PACKET_SIZE - (2 * NUM_PACKETS);
+		//The expected aggregated packet
+		Byte pExpectedAggregatedPacket[MAX_PACKET_SIZE] = {0};
+
+		//initialize the packets
+		//example: for NUM_PACKETS = 5 and MAX_PACKET_SIZE = 1024:
+		//nTotalPacketsSize will be 1024 - 5*2 = 1014
+		//packets[0] size will be 1014/5 = 202 bytes of 0
+		//packets[1] size will be (1014 - 202) / 5 = 162 bytes of 1
+		//packets[2] size will be (1014 - 201 - 162) / 5 = 130 bytes of 2
+		//packets[3] size will be (1014 - 201 - 162 - 130) / 5 = 104 bytes of 3
+		//packets[4] size will be 1014 - 201 - 162 - 130 - 104 = 416 bytes of 4
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			if (NUM_PACKETS - 1 == i)
+				pPacketsSizes[i] = nTotalPacketsSize;
+			else
+				pPacketsSizes[i] = nTotalPacketsSize / NUM_PACKETS;
+			nTotalPacketsSize -= pPacketsSizes[i];
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+				pPackets[i][j] = i + 16*test_num;
+		}
+		test_num++;
+
+		//send the packets
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+					pPacketsSizes[i]);
+			int nBytesSent = m_UsbNoAggToIpaPipeAgg.Send(pPackets[i],
+					pPacketsSizes[i]);
+			if (pPacketsSizes[i] != nBytesSent)
+			{
+				LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+						"failed!\n", i, pPacketsSizes[i]);
+				return false;
+			}
+		}
+
+		//receive the aggregated packet
+		LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be "
+				"there)\n", MAX_PACKET_SIZE);
+		int nBytesReceived = m_IpaToUsbPipeAggr.Receive(pReceivedPacket,
+				MAX_PACKET_SIZE);
+		if (MAX_PACKET_SIZE != nBytesReceived)
+		{
+			LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d "
+					"bytes) failed!\n", MAX_PACKET_SIZE);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+
+
+		//initializing the aggregated packet
+		int k = 0;
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			//the first 2 bytes are the packet length in little endian
+			pExpectedAggregatedPacket[k] = pPacketsSizes[i] & 0x00FF;
+			pExpectedAggregatedPacket[k+1] = pPacketsSizes[i] >> 8;
+			k += 2;
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+			{
+				pExpectedAggregatedPacket[k] = pPackets[i][j];
+				k++;
+			}
+		}
+
+		//comparing the received packet to the aggregated packet
+		LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+
+		bTestResult &= !memcmp(pExpectedAggregatedPacket, pReceivedPacket,
+				sizeof(pReceivedPacket));
+
+		return bTestResult;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class TLPDeaggregationTest: public TLPAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	TLPDeaggregationTest()
+	{
+		m_name = "TLPDeaggregationTest";
+		m_description = "TLP Deaggregation test - sends an aggregated packet made from"
+				"5 packets and receives 5 packets";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool Run()
+	{
+		bool bTestResult = true;
+		//The packets that the aggregated packet will be made of
+		Byte pExpectedPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+		//The real sizes of the packets that the aggregated packet will be made of
+		int pPacketsSizes[NUM_PACKETS];
+		//Buffers for the packets that will be received
+		Byte pReceivedPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+		//Total size of all the packets that the aggregated packet will be made of
+		//(this is the max size of the aggregated packet
+		//minus 2 bytes for each packet in the aggregated packet)
+		int nTotalPacketsSize = MAX_PACKET_SIZE - (2 * NUM_PACKETS);
+		//The aggregated packet that will be sent
+		Byte pAggregatedPacket[MAX_PACKET_SIZE] = {0};
+
+		//initialize the packets
+		//example: for NUM_PACKETS = 5 and MAX_PACKET_SIZE = 1024:
+		//nTotalPacketsSize will be 1024 - 5*2 = 1014
+		//packets[0] size will be 1014/5 = 202 bytes of 0
+		//packets[1] size will be (1014 - 202) / 5 = 162 bytes of 1
+		//packets[2] size will be (1014 - 201 - 162) / 5 = 130 bytes of 2
+		//packets[3] size will be (1014 - 201 - 162 - 130) / 5 = 104 bytes of 3
+		//packets[4] size will be 1014 - 201 - 162 - 130 - 104 = 416 bytes of 4
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			if (NUM_PACKETS - 1 == i)
+				pPacketsSizes[i] = nTotalPacketsSize;
+			else
+				pPacketsSizes[i] = nTotalPacketsSize / NUM_PACKETS;
+			nTotalPacketsSize -= pPacketsSizes[i];
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+				pExpectedPackets[i][j] = i+ 16*test_num;
+		}
+		test_num++;
+
+		//initializing the aggregated packet
+		int k = 0;
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			//the first 2 bytes are the packet length in little endian
+			pAggregatedPacket[k] = pPacketsSizes[i] & 0x00FF;
+			pAggregatedPacket[k+1] = pPacketsSizes[i] >> 8;
+			k += 2;
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+			{
+				pAggregatedPacket[k] = pExpectedPackets[i][j];
+				k++;
+			}
+		}
+
+		//send the aggregated packet
+		LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d bytes)\n",
+				sizeof(pAggregatedPacket));
+		int nBytesSent = m_UsbDeaggToIpaPipeNoAgg.Send(pAggregatedPacket,
+				sizeof(pAggregatedPacket));
+		if (sizeof(pAggregatedPacket) != nBytesSent)
+		{
+			LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d bytes) "
+					"failed!\n", sizeof(pAggregatedPacket));
+			return false;
+		}
+
+
+		//receive the packets
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			LOG_MSG_DEBUG("Reading packet %d from the USB pipe(%d bytes should be "
+					"there)\n", i, pPacketsSizes[i]);
+			int nBytesReceived = m_IpaToUsbPipeNoAgg.Receive(pReceivedPackets[i],
+					pPacketsSizes[i]);
+			if (pPacketsSizes[i] != nBytesReceived)
+			{
+				LOG_MSG_DEBUG("Receiving packet %d from the USB pipe(%d bytes) "
+						"failed!\n", i, pPacketsSizes[i]);
+				print_buff(pReceivedPackets[i], nBytesReceived);
+				return false;
+			}
+		}
+
+		//comparing the received packet to the aggregated packet
+		LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+		for (int i = 0; i < NUM_PACKETS; i++)
+			bTestResult &= !memcmp(pExpectedPackets[i], pReceivedPackets[i], pPacketsSizes[i]);
+
+		return bTestResult;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+
+class TLPDeaggregationAndAggregationTest: public TLPAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	TLPDeaggregationAndAggregationTest()
+	{
+		m_name = "TLPDeaggregationAndAggregationTest";
+		m_description = "TLP Deaggregation and Aggregation test - sends an aggregated "
+				"packet made from 5 packets and receives the same aggregated packet";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool Run()
+	{
+		bool bTestResult = true;
+		//The packets that the aggregated packet will be made of
+		Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+		//The real sizes of the packets that the aggregated packet will be made of
+		int pPacketsSizes[NUM_PACKETS];
+		//Buffers for the packets that will be received
+		Byte pReceivedPacket[MAX_PACKET_SIZE];
+		//Total size of all the packets that the aggregated packet will be made of
+		//(this is the max size of the aggregated packet
+		//minus 2 bytes for each packet in the aggregated packet)
+		int nTotalPacketsSize = MAX_PACKET_SIZE - (2 * NUM_PACKETS);
+		//The aggregated packet that will be sent
+		Byte pAggregatedPacket[MAX_PACKET_SIZE] = {0};
+
+		//initialize the packets
+		//example: for NUM_PACKETS = 5 and MAX_PACKET_SIZE = 1024:
+		//nTotalPacketsSize will be 1024 - 5*2 = 1014
+		//packets[0] size will be 1014/5 = 202 bytes of 0
+		//packets[1] size will be (1014 - 202) / 5 = 162 bytes of 1
+		//packets[2] size will be (1014 - 201 - 162) / 5 = 130 bytes of 2
+		//packets[3] size will be (1014 - 201 - 162 - 130) / 5 = 104 bytes of 3
+		//packets[4] size will be 1014 - 201 - 162 - 130 - 104 = 416 bytes of 4
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			if (NUM_PACKETS - 1 == i)
+				pPacketsSizes[i] = nTotalPacketsSize;
+			else
+				pPacketsSizes[i] = nTotalPacketsSize / NUM_PACKETS;
+			nTotalPacketsSize -= pPacketsSizes[i];
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+				pPackets[i][j] = i+ 16*test_num;
+		}
+		test_num++;
+
+		//initializing the aggregated packet
+		int k = 0;
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			//the first 2 bytes are the packet length in little endian
+			pAggregatedPacket[k] = pPacketsSizes[i] & 0x00FF;
+			pAggregatedPacket[k+1] = pPacketsSizes[i] >> 8;
+			k += 2;
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+			{
+				pAggregatedPacket[k] = pPackets[i][j];
+				k++;
+			}
+		}
+
+		//send the aggregated packet
+		LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d bytes)\n",
+				sizeof(pAggregatedPacket));
+		int nBytesSent = m_UsbDeaggToIpaPipeAgg.Send(pAggregatedPacket,
+				sizeof(pAggregatedPacket));
+		if (sizeof(pAggregatedPacket) != nBytesSent)
+		{
+			LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d bytes)"
+					" failed!\n", sizeof(pAggregatedPacket));
+			return false;
+		}
+
+		//receive the aggregated packet
+		LOG_MSG_DEBUG("Reading aggregated packet from the USB pipe(%d bytes "
+				"should be there)\n", sizeof(pAggregatedPacket));
+		int nBytesReceived = m_IpaToUsbPipeAggr.Receive(pReceivedPacket,
+				sizeof(pAggregatedPacket));
+		if (sizeof(pAggregatedPacket) != nBytesReceived)
+		{
+			LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d "
+					"bytes) failed!\n", sizeof(pAggregatedPacket));
+			LOG_MSG_DEBUG("Received %d bytes\n", nBytesReceived);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+print_buff(pReceivedPacket, nBytesReceived);
+
+		//comparing the received packet to the aggregated packet
+		LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+		bTestResult &= !memcmp(pAggregatedPacket, pReceivedPacket,
+				sizeof(pReceivedPacket));
+
+
+		return bTestResult;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class TLPAggregationLoopTest: public TLPAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	TLPAggregationLoopTest()
+	{
+		m_name = "TLPAggregationLoopTest";
+		m_description = "TLP Aggregation Loop test - sends 5 packets and expects to"
+				"receives 1 aggregated packet a few times";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool Run()
+	{
+		//The packets that will be sent
+		Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+		//The real sizes of the packets that will be sent
+		int pPacketsSizes[NUM_PACKETS];
+		//Buffer for the packet that will be received
+		Byte pReceivedPacket[MAX_PACKET_SIZE];
+		//Total size of all sent packets (this is the max size of the aggregated packet
+		//minus 2 bytes for each packet in the aggregated packet)
+		int nTotalPacketsSize = MAX_PACKET_SIZE - (2 * NUM_PACKETS);
+		//The expected aggregated packet
+		Byte pExpectedAggregatedPacket[MAX_PACKET_SIZE] = {0};
+
+		//initialize the packets
+		//example: for NUM_PACKETS = 5 and MAX_PACKET_SIZE = 1024:
+		//nTotalPacketsSize will be 1024 - 5*2 = 1014
+		//packets[0] size will be 1014/5 = 202 bytes of 0
+		//packets[1] size will be (1014 - 202) / 5 = 162 bytes of 1
+		//packets[2] size will be (1014 - 201 - 162) / 5 = 130 bytes of 2
+		//packets[3] size will be (1014 - 201 - 162 - 130) / 5 = 104 bytes of 3
+		//packets[4] size will be 1014 - 201 - 162 - 130 - 104 = 416 bytes of 4
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			if (NUM_PACKETS - 1 == i)
+				pPacketsSizes[i] = nTotalPacketsSize;
+			else
+				pPacketsSizes[i] = nTotalPacketsSize / NUM_PACKETS;
+			nTotalPacketsSize -= pPacketsSizes[i];
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+				pPackets[i][j] = i+ 16*test_num;
+		}
+		test_num++;
+
+		//initializing the aggregated packet
+		int k = 0;
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			//the first 2 bytes are the packet length in little endian
+			pExpectedAggregatedPacket[k] = pPacketsSizes[i] & 0x00FF;
+			pExpectedAggregatedPacket[k+1] = pPacketsSizes[i] >> 8;
+			k += 2;
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+			{
+				pExpectedAggregatedPacket[k] = pPackets[i][j];
+				k++;
+			}
+		}
+
+		for (int j = 0; j < AGGREGATION_LOOP; j++)
+		{
+			//send the packets
+			for (int i = 0; i < NUM_PACKETS; i++)
+			{
+				LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n",
+						i, pPacketsSizes[i]);
+				int nBytesSent = m_UsbNoAggToIpaPipeAgg.Send(pPackets[i],
+						pPacketsSizes[i]);
+				if (pPacketsSizes[i] != nBytesSent)
+				{
+					LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+							"failed!\n", i, pPacketsSizes[i]);
+					return false;
+				}
+			}
+
+			memset(pReceivedPacket, 0, sizeof(pReceivedPacket));
+			//receive the aggregated packet
+			LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be "
+					"there)\n", MAX_PACKET_SIZE);
+			int nBytesReceived = m_IpaToUsbPipeAggr.Receive(pReceivedPacket,
+					MAX_PACKET_SIZE);
+			if (MAX_PACKET_SIZE != nBytesReceived)
+			{
+				LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d "
+						"bytes) failed!\n", MAX_PACKET_SIZE);
+				return false;
+			}
+
+			//comparing the received packet to the aggregated packet
+			LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+
+			if (0 != memcmp(pExpectedAggregatedPacket, pReceivedPacket,
+					sizeof(pReceivedPacket)))
+			{
+				LOG_MSG_DEBUG("Comparison of packet %d failed!\n", j);
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class TLPAggregationTimeLimitTest: public TLPAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	TLPAggregationTimeLimitTest()
+	{
+		m_name = "TLPAggregationTimeLimitTest";
+		m_description = "TLP Aggregation time limit test - sends 1 packet "
+				"smaller than the byte limit and receives 1 aggregated packet";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool Run()
+	{
+		bool bTestResult = true;
+		//The packets that will be sent
+		Byte pPackets[TIME_LIMIT_NUM_PACKETS][MAX_PACKET_SIZE];
+		//The real sizes of the packets that will be sent
+		int pPacketsSizes[TIME_LIMIT_NUM_PACKETS];
+		//Buffer for the packet that will be received
+		Byte pReceivedPacket[MAX_PACKET_SIZE] = {0};
+		//The expected aggregated packet
+		Byte pExpectedAggregatedPacket[MAX_PACKET_SIZE] = {0};
+		//Size of aggregated packet
+		int nTotalPacketsSize = 0;
+
+		//initialize the packets
+		for (int i = 0; i < TIME_LIMIT_NUM_PACKETS; i++)
+		{
+			pPacketsSizes[i] = i + 1;
+			nTotalPacketsSize += pPacketsSizes[i] + 2; //size of the packet + 2 bytes for length
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+				pPackets[i][j] = i+ 16*test_num;
+		}
+		test_num++;
+
+		//send the packets
+		for (int i = 0; i < TIME_LIMIT_NUM_PACKETS; i++)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+					pPacketsSizes[i]);
+			int nBytesSent = m_UsbNoAggToIpaPipeAggTime.Send(pPackets[i],
+					pPacketsSizes[i]);
+			if (pPacketsSizes[i] != nBytesSent)
+			{
+				LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+						"failed!\n", i, pPacketsSizes[i]);
+				return false;
+			}
+		}
+
+		//receive the aggregated packet
+		LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be "
+				"there)\n", nTotalPacketsSize);
+		int nBytesReceived = m_IpaToUsbPipeAggTime.Receive(pReceivedPacket,
+				nTotalPacketsSize);
+		if (nTotalPacketsSize != nBytesReceived)
+		{
+			LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d "
+					"bytes) failed!\n", nTotalPacketsSize);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+
+		//initializing the aggregated packet
+		int k = 0;
+		for (int i = 0; i < TIME_LIMIT_NUM_PACKETS; i++)
+		{
+			//the first 2 bytes are the packet length in little endian
+			pExpectedAggregatedPacket[k] = pPacketsSizes[i] & 0x00FF;
+			pExpectedAggregatedPacket[k+1] = pPacketsSizes[i] >> 8;
+			k += 2;
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+			{
+				pExpectedAggregatedPacket[k] = pPackets[i][j];
+				k++;
+			}
+		}
+
+		//comparing the received packet to the aggregated packet
+		LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+
+		bTestResult &= !memcmp(pExpectedAggregatedPacket, pReceivedPacket,
+				sizeof(pReceivedPacket));
+
+		return bTestResult;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class TLPAggregationByteLimitTest: public TLPAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	TLPAggregationByteLimitTest()
+	{
+		m_name = "TLPAggregationByteLimitTest";
+		m_description = "TLP Aggregation byte limit test - sends 2 packets that together "
+				"are larger than the byte limit ";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool Run()
+	{
+		bool bTestResult = true;
+		//The packets that will be sent
+		Byte pPackets[2][MAX_PACKET_SIZE];
+		//The real sizes of the packets that will be sent
+		int pPacketsSizes[2];
+		//Buffer for the packet that will be received
+		Byte pReceivedPacket[2*MAX_PACKET_SIZE] = {0};
+		//The expected aggregated packet
+		Byte pExpectedAggregatedPacket[2*MAX_PACKET_SIZE] = {0};
+		//Size of aggregated packet
+		int nTotalPacketsSize = 0;
+
+		//initialize the packets
+		for (int i = 0; i < 2; i++)
+		{
+			pPacketsSizes[i] = (MAX_PACKET_SIZE / 2) + 10;
+			nTotalPacketsSize += pPacketsSizes[i] + 2;
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+				pPackets[i][j] = i+ 16*test_num;
+		}
+		test_num++;
+
+		//send the packets
+		for (int i = 0; i < 2; i++)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+					pPacketsSizes[i]);
+			int nBytesSent = m_UsbNoAggToIpaPipeAgg.Send(pPackets[i],
+					pPacketsSizes[i]);
+			if (pPacketsSizes[i] != nBytesSent)
+			{
+				LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+						"failed!\n", i, pPacketsSizes[i]);
+				return false;
+			}
+		}
+
+		//receive the aggregated packet
+		LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be "
+				"there)\n", nTotalPacketsSize);
+		int nBytesReceived = m_IpaToUsbPipeAggr.Receive(pReceivedPacket,
+				nTotalPacketsSize);
+		if (nTotalPacketsSize != nBytesReceived)
+		{
+			LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d"
+					" bytes) failed!\n", nTotalPacketsSize);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+
+
+		//initializing the aggregated packet
+		int k = 0;
+		for (int i = 0; i < 2; i++)
+		{
+			//the first 2 bytes are the packet length in little endian
+			pExpectedAggregatedPacket[k] = pPacketsSizes[i] & 0x00FF;
+			pExpectedAggregatedPacket[k+1] = pPacketsSizes[i] >> 8;
+			k += 2;
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+			{
+				pExpectedAggregatedPacket[k] = pPackets[i][j];
+				k++;
+			}
+		}
+
+		//comparing the received packet to the aggregated packet
+		LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+
+		bTestResult &= !memcmp(pExpectedAggregatedPacket, pReceivedPacket,
+				sizeof(pReceivedPacket));
+
+		return bTestResult;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class TLPAggregation2PipesTest: public TLPAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	TLPAggregation2PipesTest()
+	{
+		m_name = "TLPAggregation2PipesTest";
+		m_description = "TLP Aggregation 2 pipes test - sends 3 packets from one pipe"
+				"and an aggregated packet made of 2 packets from another pipe and "
+				"receives 1 aggregated packet made of all 5 packets";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool Run()
+	{
+		bool bTestResult = true;
+		//The packets that will be sent
+		Byte pPackets[NUM_PACKETS][MAX_PACKET_SIZE];
+		//The real sizes of the packets that will be sent
+		int pPacketsSizes[NUM_PACKETS];
+		//Buffer for the packet that will be received
+		Byte pReceivedPacket[MAX_PACKET_SIZE];
+		//Total size of all sent packets (this is the max size of the aggregated packet
+		//minus 2 bytes for each packet in the aggregated packet)
+		int nTotalPacketsSize = MAX_PACKET_SIZE - (2 * NUM_PACKETS);
+		//The expected aggregated packet
+		Byte pExpectedAggregatedPacket[MAX_PACKET_SIZE] = {0};
+		//The aggregated packet that will be sent
+		Byte pAggregatedPacket[MAX_PACKET_SIZE] = {0};
+		//The size of the sent aggregated packet
+		int nAggregatedPacketSize = 0;
+
+		//initialize the packets
+		//example: for NUM_PACKETS = 5 and MAX_PACKET_SIZE = 1024:
+		//nTotalPacketsSize will be 1024 - 5*2 = 1014
+		//packets[0] size will be 1014/5 = 202 bytes of 0
+		//packets[1] size will be (1014 - 202) / 5 = 162 bytes of 1
+		//packets[2] size will be (1014 - 201 - 162) / 5 = 130 bytes of 2
+		//packets[3] size will be (1014 - 201 - 162 - 130) / 5 = 104 bytes of 3
+		//packets[4] size will be 1014 - 201 - 162 - 130 - 104 = 416 bytes of 4
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			if (NUM_PACKETS - 1 == i)
+				pPacketsSizes[i] = nTotalPacketsSize;
+			else
+				pPacketsSizes[i] = nTotalPacketsSize / NUM_PACKETS;
+			nTotalPacketsSize -= pPacketsSizes[i];
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+				pPackets[i][j] = i+ 16*test_num;
+		}
+		test_num++;
+
+		//initializing the aggregated packet
+		int k = 0;
+		for (int i = 0; i < 2; i++)
+		{
+			nAggregatedPacketSize += pPacketsSizes[i] + 2;
+			//the first 2 bytes are the packet length in little endian
+			pAggregatedPacket[k] = pPacketsSizes[i] & 0x00FF;
+			pAggregatedPacket[k+1] = pPacketsSizes[i] >> 8;
+			k += 2;
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+			{
+				pAggregatedPacket[k] = pPackets[i][j];
+				k++;
+			}
+		}
+
+		//send the aggregated packet
+		LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d "
+				"bytes)\n", nAggregatedPacketSize);
+		int nBytesSent = m_UsbDeaggToIpaPipeAgg.Send(pAggregatedPacket,
+				nAggregatedPacketSize);
+		if (nAggregatedPacketSize != nBytesSent)
+		{
+			LOG_MSG_DEBUG("Sending aggregated packet into the USB pipe(%d "
+					"bytes) failed!\n", nAggregatedPacketSize);
+			return false;
+		}
+
+		//send the packets
+		for (int i = 2; i < NUM_PACKETS; i++)
+		{
+			LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n", i,
+					pPacketsSizes[i]);
+			int nBytesSent = m_UsbNoAggToIpaPipeAgg.Send(pPackets[i],
+					pPacketsSizes[i]);
+			if (pPacketsSizes[i] != nBytesSent)
+			{
+				LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes) "
+						"failed!\n", i, pPacketsSizes[i]);
+				return false;
+			}
+		}
+
+		//receive the aggregated packet
+		LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be "
+				"there)\n", MAX_PACKET_SIZE);
+		int nBytesReceived = m_IpaToUsbPipeAggr.Receive(pReceivedPacket,
+				MAX_PACKET_SIZE);
+		if (MAX_PACKET_SIZE != nBytesReceived)
+		{
+			LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d "
+					"bytes) failed!\n", MAX_PACKET_SIZE);
+			print_buff(pReceivedPacket, nBytesReceived);
+			return false;
+		}
+
+
+		//initializing the aggregated packet
+		k = 0;
+		for (int i = 0; i < NUM_PACKETS; i++)
+		{
+			//the first 2 bytes are the packet length in little endian
+			pExpectedAggregatedPacket[k] = pPacketsSizes[i] & 0x00FF;
+			pExpectedAggregatedPacket[k+1] = pPacketsSizes[i] >> 8;
+			k += 2;
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+			{
+				pExpectedAggregatedPacket[k] = pPackets[i][j];
+				k++;
+			}
+		}
+
+		//comparing the received packet to the aggregated packet
+		LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+
+		bTestResult &= !memcmp(pExpectedAggregatedPacket, pReceivedPacket,
+				sizeof(pReceivedPacket));
+
+		return bTestResult;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+class TLPAggregationTimeLimitLoopTest: public TLPAggregationTestFixture {
+public:
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	TLPAggregationTimeLimitLoopTest()
+	{
+		m_name = "TLPAggregationTimeLimitLoopTest";
+		m_description = "TLP Aggregation time limit loop test - sends 1 packet "
+				"smaller than the byte limit and receives 1 aggregated packets";
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	bool Run()
+	{
+		//The packets that will be sent
+		Byte pPackets[TIME_LIMIT_NUM_PACKETS][MAX_PACKET_SIZE];
+		//The real sizes of the packets that will be sent
+		int pPacketsSizes[TIME_LIMIT_NUM_PACKETS];
+		//Buffer for the packet that will be received
+		Byte pReceivedPacket[MAX_PACKET_SIZE] = {0};
+		//The expected aggregated packet
+		Byte pExpectedAggregatedPacket[MAX_PACKET_SIZE] = {0};
+		//Size of aggregated packet
+		int nTotalPacketsSize = 0;
+
+		//initialize the packets
+		for (int i = 0; i < TIME_LIMIT_NUM_PACKETS; i++)
+		{
+			pPacketsSizes[i] = i + 1;
+			nTotalPacketsSize += pPacketsSizes[i] + 2; //size of the packet + 2 bytes for length
+			for (int j = 0; j < pPacketsSizes[i]; j++)
+				pPackets[i][j] = i+ 16*test_num;
+		}
+		test_num++;
+
+		for (int n = 0; n < NUM_PACKETS; n++)
+		{
+			//send the packets
+			for (int i = 0; i < TIME_LIMIT_NUM_PACKETS; i++)
+			{
+				LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d bytes)\n",
+						i, pPacketsSizes[i]);
+				int nBytesSent = m_UsbNoAggToIpaPipeAggTime.Send(pPackets[i],
+						pPacketsSizes[i]);
+				if (pPacketsSizes[i] != nBytesSent)
+				{
+					LOG_MSG_DEBUG("Sending packet %d into the USB pipe(%d "
+							"bytes) failed!\n", i, pPacketsSizes[i]);
+					return false;
+				}
+			}
+
+			//receive the aggregated packet
+			LOG_MSG_DEBUG("Reading packet from the USB pipe(%d bytes should be "
+					"there)\n", nTotalPacketsSize);
+			int nBytesReceived = m_IpaToUsbPipeAggTime.Receive(pReceivedPacket,
+					nTotalPacketsSize);
+			if (nTotalPacketsSize != nBytesReceived)
+			{
+				LOG_MSG_DEBUG("Receiving aggregated packet from the USB pipe(%d "
+						"bytes) failed!\n", nTotalPacketsSize);
+				print_buff(pReceivedPacket, nBytesReceived);
+				return false;
+			}
+
+			//initializing the aggregated packet
+			int k = 0;
+			for (int i = 0; i < TIME_LIMIT_NUM_PACKETS; i++)
+			{
+				//the first 2 bytes are the packet length in little endian
+				pExpectedAggregatedPacket[k] = pPacketsSizes[i] & 0x00FF;
+				pExpectedAggregatedPacket[k+1] = pPacketsSizes[i] >> 8;
+				k += 2;
+				for (int j = 0; j < pPacketsSizes[i]; j++)
+				{
+					pExpectedAggregatedPacket[k] = pPackets[i][j];
+					k++;
+				}
+			}
+
+			//comparing the received packet to the aggregated packet
+			LOG_MSG_DEBUG("Checking sent.vs.received packet\n");
+			if (0 != memcmp(pExpectedAggregatedPacket, pReceivedPacket,
+					sizeof(pReceivedPacket)))
+			{
+				LOG_MSG_DEBUG("Comparison of packet %d failed!\n", n);
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////
+};
+
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+//Those tests should be run with configuration number 8.
+//Please look at the Fixture for more configurations update.
+static TLPAggregationTest tlpAggregationTest;
+static TLPDeaggregationTest tlpDeaggregationTest;
+static TLPAggregationLoopTest tlpAggregationLoopTest;
+static TLPAggregationTimeLimitTest tlpAggregationTimeLimitTest;
+static TLPAggregationByteLimitTest tlpAggregationByteLimitTest;
+static TLPAggregation2PipesTest tlpAggregation2PipesTest;
+static TLPAggregationTimeLimitLoopTest tlpAggregationTimeLimitLoopTest;
+static TLPDeaggregationAndAggregationTest tlpDeaggregationAndAggregationTest;
+
+/////////////////////////////////////////////////////////////////////////////////
+//                                  EOF                                      ////
+/////////////////////////////////////////////////////////////////////////////////

+ 74 - 0
kernel-tests/TestBase.cpp

@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "TestBase.h"
+#include "TestManager.h"
+#include "linux/msm_ipa.h"
+
+//////////////////////////////////////////////////////////////////////
+
+TestBase::TestBase() :
+		m_runInRegression(true),
+		m_minIPAHwType(IPA_HW_v1_1),
+		m_maxIPAHwType(IPA_HW_MAX)
+{
+	m_mem_type = DFLT_NAT_MEM_TYPE;
+}
+
+//////////////////////////////////////////////////////////////////////
+
+void TestBase::Register(TestBase &test)
+{
+	TestManager::GetInstance()->Register(test);
+}
+
+//////////////////////////////////////////////////////////////////////
+
+//Empty default implementation, a test does not have to implement Setup()
+bool TestBase::Setup()
+{
+	return true;
+}
+
+//////////////////////////////////////////////////////////////////////
+
+//Empty default implementation, a test does not have to implement Teardown()
+bool TestBase::Teardown()
+{
+	return true;
+}
+
+//////////////////////////////////////////////////////////////////////
+
+TestBase::~TestBase()
+{
+
+}
+
+//////////////////////////////////////////////////////////////////////

+ 74 - 0
kernel-tests/TestBase.h

@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TEST_BASE_H_
+#define _TEST_BASE_H_
+
+#include <string>
+#include <vector>
+
+#define DFLT_NAT_MEM_TYPE "HYBRID"
+
+using namespace std;
+
+class TestBase
+{
+public:
+	virtual bool Setup();
+	/* Empty default implementation,
+	 * a test does not have to implement Setup()
+	 */
+	virtual bool Run() = 0;
+	/* A test must implement Run() */
+	virtual bool Teardown();
+	/* Empty default implementation,
+	 * a test does not have to implement Teardown()
+	 */
+	void Register(TestBase & test);
+	virtual ~TestBase();
+	TestBase();
+	void SetMemType(
+		const char* mem_type = DFLT_NAT_MEM_TYPE)
+	{
+		m_mem_type = mem_type;
+	}
+
+	const char* m_mem_type;
+	string m_name;
+	string m_description;
+	vector < string > m_testSuiteName;
+	/* Every test can belong to multiple test suites */
+	bool m_runInRegression;
+	/* Should this test be run in a regression test ? (Default is yes) */
+	int m_minIPAHwType;
+	/* The minimal IPA HW version which this test can run on */
+	int m_maxIPAHwType;
+	/* The maximal IPA HW version which this test can run on */
+};
+#endif

+ 396 - 0
kernel-tests/TestManager.cpp

@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2017-2018,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <algorithm>	// std::find
+#include <vector>	// std::vector
+#include <string>
+#include <errno.h>
+#include <ctime>
+#include <sstream>
+#include "TestManager.h"
+#include "TestsUtils.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include "ipa_test_module.h"
+#include <sys/ioctl.h>
+
+using namespace std;
+
+/* Global static pointer used to ensure a single instance of the class. */
+TestManager* TestManager::m_instance = NULL;
+
+
+#ifdef HAVE_LIBXML
+
+TestsXMLResult::TestsXMLResult()
+{
+	xmlNodePtr node;
+
+	// initialize xml report document and add a root to node it
+	m_XML_doc_ptr = xmlNewDoc(BAD_CAST "1.0");
+	if (m_XML_doc_ptr == NULL){
+		printf("error on allocation xml doc\n");
+		exit(-1);
+	}
+
+	node = xmlNewNode(NULL, BAD_CAST "testsuites");
+	if (!node) {
+		printf("failed to allocate XML node\n");
+		exit (-1);
+	}
+	xmlDocSetRootElement(m_XML_doc_ptr, node);
+}
+
+TestsXMLResult::~TestsXMLResult()
+{
+	if (m_XML_doc_ptr)
+		xmlFreeDoc(m_XML_doc_ptr);
+	xmlCleanupParser();
+}
+
+/*
+ * Returns xmlPtr to testsuite element node, if doesn't exist
+ * creates one by that name
+ */
+xmlNodePtr TestsXMLResult::GetSuiteElement(const string& suite_name)
+{
+	xmlNodePtr root_node, suite_node, new_child_node;
+
+	if (!m_XML_doc_ptr) {
+		printf("no xml document\n");
+		return NULL;
+	}
+
+	root_node = xmlDocGetRootElement(m_XML_doc_ptr);
+	suite_node = xmlFirstElementChild(root_node);
+	while (suite_node)
+	{
+		/* get suite name */
+		xmlChar *val = xmlGetProp(suite_node, BAD_CAST "name");
+
+		/* change xmlCHar* to string */
+		string node_suite_name(reinterpret_cast<char*>(val));
+		xmlFree(val);			//free val allocated memory
+
+		if (node_suite_name == suite_name)
+			return suite_node;
+		else suite_node = suite_node->next;
+	}
+
+	/* If we got here no suitable suite name was found,
+	 * so we create a new suite element and return it
+	 */
+	new_child_node = xmlNewChild(root_node, NULL, BAD_CAST "testsuite", BAD_CAST "");
+	if (!new_child_node) {
+		printf("failed creating new XML node\n");
+		return NULL;
+	}
+	xmlSetProp(new_child_node, BAD_CAST "name", BAD_CAST suite_name.c_str());
+
+	return xmlGetLastChild(root_node);
+}
+
+/*
+ * Creates new testcase element
+ */
+void TestsXMLResult::AddTestcase(const string &suite_nm, const string &test_nm,
+	double runtime, bool pass)
+{
+	xmlNodePtr suite_node, new_testcase, fail_node;
+	ostringstream runtime_str;
+
+	if (!suite_nm.size() || !test_nm.size()) {
+		printf("Input error: suite_nm size %d , test_nm size %d",
+			suite_nm.size(), test_nm.size());
+		exit(-1);
+	}
+
+	suite_node = GetSuiteElement(suite_nm);
+	if (!suite_node) {
+		printf("failed getting suite element\n");
+		exit(-1);
+	}
+
+	/* Create new testcase element as son to suite element */
+	new_testcase = xmlNewChild(suite_node, NULL, BAD_CAST "testcase", NULL);
+	if (!new_testcase) {
+		printf("failed creating XML new child for testcase\n");
+		exit(-1);
+	}
+	xmlSetProp(new_testcase, BAD_CAST "name", BAD_CAST test_nm.c_str());
+
+	runtime_str << runtime;
+	xmlSetProp(new_testcase, BAD_CAST "time", BAD_CAST runtime_str.str().c_str());
+
+	if (!pass) {
+		fail_node = xmlNewChild(new_testcase, NULL, BAD_CAST "failure", NULL);
+		if (!fail_node) {
+			printf("failed creating fail node\n");
+			exit(-1);
+		}
+	}
+}
+
+/*
+ * Prints the XML tree to file
+ */
+void TestsXMLResult::GenerateXMLReport(void)
+{
+	if (!m_XML_doc_ptr) {
+		printf("no xml document\n");
+		return;
+	}
+
+	xmlSaveFormatFileEnc(XUNIT_REPORT_PATH_AND_NAME, m_XML_doc_ptr, "UTF-8", 1);
+}
+
+#else /* HAVE_LIBXML */
+
+TestsXMLResult::TestsXMLResult() {}
+TestsXMLResult::~TestsXMLResult() {}
+void TestsXMLResult::AddTestcase(const string &suite_nm, const string &test_nm,
+	double runtime, bool pass) {}
+void TestsXMLResult::GenerateXMLReport(void)
+{
+	printf("No XML support\n");
+}
+
+#endif /* HAVE_LIBXML */
+
+TestManager::TestManager(
+    const char* nat_mem_type_ptr)
+{
+	m_testList.clear();
+	m_failedTestsNames.clear();
+	m_numTestsFailed = 0;
+	m_numTestsRun = 0;
+	FetchIPAHwType();
+	m_nat_mem_type_ptr = nat_mem_type_ptr;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+TestManager::~TestManager()
+{
+	m_testList.clear();
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+TestManager* TestManager::GetInstance(
+	const char* nat_mem_type_ptr)
+{
+	if (!m_instance)   // Only allow one instance of class to be generated.
+		m_instance = new TestManager(nat_mem_type_ptr);
+
+	return m_instance;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+void TestManager::Register(TestBase &test)
+{
+	m_testList.push_back(&test);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+bool TestManager::Run(vector<string> testSuiteList, vector<string> testNameList)
+{
+	TestBase *test = NULL;
+	bool pass = true;
+	vector<string>::iterator testIter;
+	vector<string>::iterator testSuiteIter;
+	bool runTest = false;
+	clock_t begin_test_clk, end_test_clk;
+	double test_runtime_sec = 0, total_time_sec = 0;
+	TestsXMLResult xml_res;
+
+	if (m_testList.size() == 0)
+		return false;
+
+	/* PrintRegisteredTests(); */
+
+	for (unsigned int i = 0 ; i < m_testList.size() ; i++ , runTest = false) {
+		pass = true;
+		test = m_testList[i];
+
+		// Run only tests from the list of test suites which is stated in the command
+		// line. In case the list is empty, run all tests.
+		if (testSuiteList.size() > 0) {
+			for (unsigned int j = 0; j < test->m_testSuiteName.size(); j++) {
+				testSuiteIter = find(testSuiteList.begin(), testSuiteList.end(), test->m_testSuiteName[j]);
+				if (testSuiteIter != testSuiteList.end()) {
+					runTest = true;
+				}
+			}
+		}
+
+		// We also support test by name
+		if (testNameList.size() > 0) {
+			testIter = find(testNameList.begin(), testNameList.end(), test->m_name);
+			if (testIter != testNameList.end())
+				runTest = true;
+		}
+
+		// Run the test only if it's applicable to the current IPA HW type / version
+		if (runTest) {
+			if (!(m_IPAHwType >= test->m_minIPAHwType && m_IPAHwType <= test->m_maxIPAHwType))
+				runTest = false;
+		}
+
+		if (!runTest)
+			continue;
+
+		printf("\n\nExecuting test %s\n", test->m_name.c_str());
+		printf("Description: %s\n", test->m_description.c_str());
+
+		printf("Setup()\n");
+		begin_test_clk = clock();
+		test->SetMemType(GetMemType());
+		pass &= test->Setup();
+
+		//In case the test's setup did not go well it will be a bad idea to try and run it.
+		if (true == pass)
+		{
+			printf("Run()\n");
+			pass &= test->Run();
+		}
+
+		printf("Teardown()\n");
+		pass &= test->Teardown();
+
+		end_test_clk = clock();
+		test_runtime_sec = double(end_test_clk - begin_test_clk) / CLOCKS_PER_SEC;
+		total_time_sec += test_runtime_sec;
+
+		if (pass)
+		{
+			m_numTestsRun++;
+			PrintSeparator(test->m_name.size());
+			printf("Test %s PASSED ! time:%g\n", test->m_name.c_str(), test_runtime_sec);
+			PrintSeparator(test->m_name.size());
+		}
+		else
+		{
+			m_numTestsRun++;
+			m_numTestsFailed++;
+			m_failedTestsNames.push_back(test->m_name);
+			PrintSeparator(test->m_name.size());
+			printf("Test %s FAILED ! time:%g\n", test->m_name.c_str(), test_runtime_sec);
+			PrintSeparator(test->m_name.size());
+		}
+
+		xml_res.AddTestcase(test->m_testSuiteName[0], test->m_name, test_runtime_sec, pass);
+	} // for
+
+	// Print summary
+	printf("\n\n");
+	printf("==================== RESULTS SUMMARY ========================\n");
+	printf("%zu tests were run, %zu failed, total time:%g.\n", m_numTestsRun, m_numTestsFailed, total_time_sec);
+	if (0 != m_numTestsFailed) {
+		printf("Failed tests list:\n");
+		for (size_t i = 0; i < m_numTestsFailed; i++) {
+			printf("        %s\n", m_failedTestsNames[i].c_str());
+			m_failedTestsNames.pop_back();
+		}
+	}
+	printf("=============================================================\n");
+	xml_res.GenerateXMLReport();
+
+	return pass;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+void TestManager::PrintSeparator(size_t len)
+{
+	string separator;
+
+	for (size_t i = 0; i < len + 15; i++) {
+		separator += "-";
+	}
+
+	printf("%s\n", separator.c_str());
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+TestManager::TestManager(TestManager const&)
+{
+
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+TestManager& TestManager::operator=(TestManager const&)
+{
+	return *m_instance;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+void TestManager::PrintRegisteredTests()
+{
+	printf("Test list: (%zu registered)\n", m_testList.size());
+	for (unsigned int i = 0; i < m_testList.size(); i++) {
+		printf("%d) name = %s, suite name = %s, regression = %d\n", i, m_testList[i]->m_name.c_str(),
+		       m_testList[i]->m_testSuiteName[0].c_str(), m_testList[i]->m_runInRegression);
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+void TestManager::FetchIPAHwType()
+{
+	int fd;
+
+	// Open ipa_test device node
+	fd = open("/dev/ipa_test" , O_RDONLY);
+	if (fd < 0) {
+		printf("Failed opening %s. errno %d: %s\n", "/dev/ipa_test", errno, strerror(errno));
+		m_IPAHwType = IPA_HW_None;
+		return;
+	}
+
+	printf("%s(), fd is %d\n", __FUNCTION__, fd);
+
+	m_IPAHwType = (enum ipa_hw_type)ioctl(fd, IPA_TEST_IOC_GET_HW_TYPE);
+	if (-1 == m_IPAHwType) {
+		printf("%s(), IPA_TEST_IOC_GET_HW_TYPE ioctl failed\n", __FUNCTION__);
+		m_IPAHwType = IPA_HW_None;
+	}
+
+	printf("%s(), IPA HW type (version) = %d\n", __FUNCTION__, m_IPAHwType);
+	close(fd);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////

+ 103 - 0
kernel-tests/TestManager.h

@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017-2018,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TEST_MANAGER_H_
+#define _TEST_MANAGER_H_
+
+#include "TestBase.h"
+#include <vector>
+#include <string>
+#include "linux/msm_ipa.h"
+
+#ifdef HAVE_LIBXML
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#endif
+
+using namespace std;
+
+
+class TestsXMLResult
+{
+public:
+	TestsXMLResult();
+	~TestsXMLResult();
+	void AddTestcase(const string &suite_nm, const string &test_nm,
+		double runtime, bool pass);
+	void GenerateXMLReport(void);
+private:
+#ifdef HAVE_LIBXML
+	xmlNodePtr GetSuiteElement(const string& suite_name);
+	xmlDocPtr m_XML_doc_ptr;
+#endif
+};
+
+class TestManager /* Singleton */
+{
+public:
+	static TestManager *GetInstance(
+		const char* nat_mem_type_ptr = DFLT_NAT_MEM_TYPE);
+	~TestManager();
+	void Register(TestBase & test);
+	bool Setup();
+	/* This is the place to put initialization
+	 * for the whole test framework
+	 */
+	bool Run(vector <string> testSuiteList,
+		 vector <string> testNameList);
+	/* This function will run all the tests in the system */
+	bool Teardown();
+	/* This is the place to put tear-down for the whole test framework */
+	vector < TestBase * > m_testList;
+	/* Holds pointers to all of the tests in the system */
+
+	enum ipa_hw_type GetIPAHwType() {return m_IPAHwType;}
+	const char* GetMemType() { return m_nat_mem_type_ptr; }
+
+private:
+	TestManager(
+		const char* nat_mem_type_ptr = DFLT_NAT_MEM_TYPE);
+	TestManager(TestManager const &);
+	TestManager & operator = (TestManager const &);
+	void PrintSeparator(size_t len);
+	void PrintRegisteredTests();
+	void BuildRegressionTestSuite();
+	void FetchIPAHwType();
+
+	static TestManager *m_instance;
+
+	size_t m_numTestsRun;
+	size_t m_numTestsFailed;
+	enum ipa_hw_type m_IPAHwType;
+	const char* m_nat_mem_type_ptr;
+
+	vector < string > m_failedTestsNames;
+};
+
+#endif

+ 1814 - 0
kernel-tests/TestsUtils.cpp

@@ -0,0 +1,1814 @@
+/*
+ * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include "TestsUtils.h"
+#include "InterfaceAbstraction.h"
+#include "Constants.h"
+#include "Pipe.h"
+
+using namespace std;
+///////////////////////////////////////////////////////////////////////////////
+
+extern Logger g_Logger;
+
+static uint8_t IPv4Packet[IP4_PACKET_SIZE] = {
+		0x45, 0x00, 0x00, 0x2e,
+		0x00, 0x00, 0x40, 0x00,
+		0xff, 0x06, 0xf5, 0xfd,// Protocol = 06 (TCP)
+		0xc0, 0xa8, 0x02, 0x13,// IPv4 SRC Addr 192.168.2.19
+		0xc0, 0xa8, 0x02, 0x68,// IPv4 DST Addr 192.168.2.104
+		0x04, 0x57, 0x08, 0xae,
+		0x00, 0x00, 0x30, 0x34,
+		0x00, 0x00, 0x00, 0x50,
+		0x50, 0xc1, 0x40, 0x00,
+		0xab, 0xc9, 0x00, 0x00,
+		0x00, 0xaa, 0xaa, 0xaa,
+		0xbb, 0xbb, 0xbb, 0xbb,
+		0xbb, 0xbb, 0xbb, 0xbb,
+		0xbb, 0xbb, 0xbb, 0xbb,
+		0xbb, 0xbb, 0xbb, 0xbb,
+		0xbb, 0xbb, 0xbb, 0xbb,
+		0xbb, 0xbb, 0xbb, 0xbb,
+		0xbb, 0xbb
+};
+
+static uint8_t IPv6Packet[] = {
+		0x60, 0x00, 0x00, 0x00,
+		0x00, 0x1c, 0x06, 0x01, // Protocol = 6 (TCP)
+		0xfe, 0x80, 0x00, 0x00, // source address (16B)
+		0x00, 0x00, 0x00, 0x00,
+		0xd9, 0xf9, 0xce, 0x5e,
+		0x02, 0xec, 0x32, 0x99,
+		0xff, 0x02, 0x00, 0x00, // dst address (16B)
+		0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x0c,
+		0x12, 0x34, 0x12, 0x34, // port src = 0x1234 dest = 0x1234
+		0x00, 0x14, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00,
+		0x60, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, // options
+		0xda, 0x7a, 0xda, 0x7a // payload
+};
+
+static uint8_t IPv6PacketFragExtHdr[] = {
+		0x60, 0x00, 0x00, 0x00,
+		0x00, 0x0c, 0x2C, 0x01, // Next header = FRAGMENT HEADER(44)
+		0xfe, 0x80, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00,
+		0xd9, 0xf9, 0xce, 0x5e,
+		0x02, 0xec, 0x32, 0x99,
+		0xff, 0x02, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x0c,
+		0x06, 0x00, 0x00, 0x00, // fragment header, Protocol = 6 (TCP)
+		0x00, 0x00, 0x00, 0x00,
+		0x12, 0x34, 0x12, 0x34, // port src = 0x1234 dest = 0x1234
+		0x00, 0x14, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00,
+		0x60, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00,
+		0xda, 0x7a, 0xda, 0x7a  // payload
+};
+
+static const uint8_t Eth2IPv4Packet[] =
+{
+	// ETH2 - 14 bytes
+	0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x11, // ETH2 DST
+	0x22, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, // ETH2 SRC
+	0x08, 0x00,		// ETH2 TYPE IPv4 - ETH_P_IP 0x0800
+
+	// IPv4
+	0x45, 0x00, 0x00, 0x2e,
+	0x00, 0x00, 0x40, 0x00,
+	0xff, 0x06, 0xf5, 0xfd, // Protocol = 06 (TCP)
+	0xc0, 0xa8, 0x02, 0x13, // IPv4 SRC Addr 192.168.2.19
+	0xc0, 0xa8, 0x02, 0x68, // IPv4 DST Addr 192.168.2.104
+	0x04, 0x57, 0x08, 0xae,
+	0x00, 0x00, 0x30, 0x34,
+	0x00, 0x00, 0x00, 0x50,
+	0x50, 0xc1, 0x40, 0x00,
+	0xab, 0xc9, 0x00, 0x00,
+	0x00
+};
+
+static const uint8_t Eth2IPv6Packet[] =
+{
+	// ETH2 - 14 bytes
+	0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x11, // ETH2 DST
+	0x22, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, // ETH2 SRC
+	0x86, 0xdd,		// ETH2 TYPE IPv6 - ETH_P_IPV6 x86DD
+
+	// IPv6
+	0x60, 0x00, 0x00, 0x00,
+	0x02, 0x12, 0x11, 0x01,
+	0xfe, 0x80, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0xd9, 0xf9, 0xce, 0x5e,
+	0x02, 0xec, 0x32, 0x99,
+	0xff, 0x02, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x0c
+};
+
+static const uint8_t WLANEth2IPv4Packet[] =
+{
+	// WLAN
+	0xa1, 0xb2, 0xc3, 0xd4,			// WLAN hdr
+
+	// ETH2 - 14 bytes
+	0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x11,	// ETH2 DST
+	0x22, 0xee, 0xdd, 0xcc, 0xbb, 0xaa,	// ETH2 SRC
+	0x08, 0x00,			// ETH2 TYPE IPv4 - ETH_P_IP 0x0800
+
+	// IPv4
+	0x45, 0x00, 0x00, 0x2e,
+	0x00, 0x00, 0x40, 0x00,
+	0xff, 0x06, 0xf5, 0xfd,	// Protocol = 06 (TCP)
+	0xc0, 0xa8, 0x02, 0x13,	// IPv4 SRC Addr 192.168.2.19
+	0xc0, 0xa8, 0x02, 0x68,	// IPv4 DST Addr 192.168.2.104
+	0x04, 0x57, 0x08, 0xae,
+	0x00, 0x00, 0x30, 0x34,
+	0x00, 0x00, 0x00, 0x50,
+	0x50, 0xc1, 0x40, 0x00,
+	0xab, 0xc9, 0x00, 0x00,
+	0x00
+};
+
+static const uint8_t WLAN802_3IPv4Packet[] =
+{
+	// WLAN
+	0xa1, 0xb2, 0xc3, 0xd4,			// WLAN hdr
+
+	// 802_3 - 26 bytes
+	0xa5, 0xb6, 0xc7, 0xd8, // ROME proprietary header
+	0xa0, 0xb1, 0xc2, 0xd3, 0xe4, 0x33,	// 802_3 DST
+	0x44, 0xb2, 0xc3, 0xd4, 0xe5, 0xf6,	// 802_3 SRC
+	0x00, IP4_PACKET_SIZE,			// 802_3 length
+	0x04, 0x15, 0x26, 0x37, 0x48, 0x59,	// LLC/SNAP
+	0x08, 0x00,				// Ethrtype - 0x0800
+
+	// IPv4
+	0x45, 0x00, 0x00, 0x2e,
+	0x00, 0x00, 0x40, 0x00,
+	0xff, 0x06, 0xf5, 0xfd,	// Protocol = 06 (TCP)
+	0xc0, 0xa8, 0x02, 0x13,	// IPv4 SRC Addr 192.168.2.19
+	0xc0, 0xa8, 0x02, 0x68,	// IPv4 DST Addr 192.168.2.104
+	0x04, 0x57, 0x08, 0xae,
+	0x00, 0x00, 0x30, 0x34,
+	0x00, 0x00, 0x00, 0x50,
+	0x50, 0xc1, 0x40, 0x00,
+	0xab, 0xc9, 0x00, 0x00,
+	0x00
+};
+
+static uint8_t IPv4_TCP_No_Payload_Packet[] = {
+		0x45, 0x00, 0x00, 0x28, // Total length is 40
+		0x00, 0x00, 0x40, 0x00,
+		0xff, 0x06, 0xf5, 0xfd,	// Protocol = 06 (TCP)
+		0xc0, 0xa8, 0x02, 0x13,	// IPv4 SRC Addr 192.168.2.19
+		0xc0, 0xa8, 0x02, 0xc8,	// IPv4 DST Addr 192.168.2.200
+		0x04, 0x57, 0x08, 0xae,
+		0x00, 0x00, 0x30, 0x34,
+		0x00, 0x00, 0x00, 0x50,
+		0x50, 0xc1, 0x40, 0x00,
+		0xab, 0xc9, 0x00, 0x00,
+};
+
+static uint8_t IPv6_TCP_No_Payload_Packet[] = {
+		0x60, 0x00, 0x00, 0x00,
+		0x00, 0x14, 0x06, 0x01, // Payload is 20 Bytes (TCP header only)
+		0xfe, 0x80, 0x00, 0x00, // SRC Addr
+		0x00, 0x00, 0x00, 0x00,
+		0xd9, 0xf9, 0xce, 0x5e,
+		0x02, 0xec, 0x32, 0x99,
+		0xff, 0x02, 0x00, 0x00, // DST Addr
+		0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x4b,
+		0x04, 0x57, 0x08, 0xae, // TCP header
+		0x00, 0x00, 0x30, 0x34,
+		0x00, 0x00, 0x00, 0x50,
+		0x50, 0xc1, 0x40, 0x00,
+		0xab, 0xc9, 0x00, 0x00,
+};
+
+static const uint8_t Eth2IPv4Packet802_1Q_tag[] =
+{
+		// ETH2 + 8021Q - 14 + 4 bytes
+		0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x11,	// ETH2 DST
+		0x22, 0xee, 0xdd, 0xcc, 0xbb, 0xaa,	// ETH2 SRC
+		0x81, 0x00, 0x20, 0x03,			// 802.1Q header with VLAN ID = 3
+		0x08, 0x00,				// ETH2 TYPE IPv4 - ETH_P_IP 0x0800
+							// IPv4
+		0x45, 0x00, 0x00, 0x2e,
+		0x00, 0x00, 0x40, 0x00,
+		0xff, 0x06, 0xf5, 0xfd,			// Protocol = 06 (TCP)
+		0xc0, 0xa8, 0x02, 0x13,			// IPv4 SRC Addr 192.168.2.19
+		0xc0, 0xa8, 0x02, 0x68,			// IPv4 DST Addr 192.168.2.104
+		0x04, 0x57, 0x08, 0xae,
+		0x00, 0x00, 0x30, 0x34,
+		0x00, 0x00, 0x00, 0x50,
+		0x50, 0xc1, 0x40, 0x00,
+		0xab, 0xc9, 0x00, 0x00,
+		0x00
+};
+
+static struct ipa_test_config_header *current_configuration = NULL;
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+*@brief Function loads a default IPv4 / IPv6 Packet
+*
+*@param [in] eIP - Type of Packet to load (IPA_IP_v4 / IPA_IP_v6)
+*@param [in] pBuffer - pointer to the destination buffer
+*@param [in,out] nMaxSize - The size of the buffer.*Upon function return,
+*	the total number of bytes copied will be stored in this parameter.
+*@return boolean indicating whether the operation completed successfully or not.
+*@details Function loads a default IPv4 / IPv6 packet into pBuffer.
+*/
+bool LoadDefaultPacket(
+	enum ipa_ip_type eIP,
+	enum ipv6_ext_hdr_type extHdrType,
+	uint8_t *pBuffer,
+	size_t &nMaxSize)
+{
+	if (IPA_IP_v4 == eIP) {
+		if (nMaxSize < sizeof(IPv4Packet))
+		{
+			LOG_MSG_ERROR("Buffer is smaller than %d, no Data was copied.",sizeof(IPv4Packet));
+			return false;
+		}
+		memcpy(pBuffer,IPv4Packet, sizeof(IPv4Packet));
+		nMaxSize = sizeof(IPv4Packet);
+		return true;
+	} else {
+		if (extHdrType == FRAGMENT)
+		{
+			if (nMaxSize < sizeof(IPv6PacketFragExtHdr))
+			{
+				LOG_MSG_ERROR("Buffer is smaller than %d, no Data was copied.",sizeof(IPv6PacketFragExtHdr));
+				return false;
+			}
+			memcpy(pBuffer,IPv6PacketFragExtHdr, sizeof(IPv6PacketFragExtHdr));
+			nMaxSize = sizeof(IPv6PacketFragExtHdr);
+
+		}
+		else
+		{
+			if (nMaxSize < sizeof(IPv6Packet))
+			{
+				LOG_MSG_ERROR("Buffer is smaller than %d, no Data was copied.",sizeof(IPv6Packet));
+				return false;
+			}
+			memcpy(pBuffer,IPv6Packet, sizeof(IPv6Packet));
+			nMaxSize = sizeof(IPv6Packet);
+		}
+		return true;
+	}
+}
+
+bool LoadDefaultPacket(enum ipa_ip_type eIP, uint8_t *pBuffer, size_t &nMaxSize)
+{
+	return LoadDefaultPacket(eIP, NONE, pBuffer, nMaxSize);
+}
+
+bool LoadNoPayloadPacket(enum ipa_ip_type eIP, uint8_t *pBuffer, size_t &nMaxSize)
+{
+	if (IPA_IP_v4 == eIP) {
+		if (nMaxSize < sizeof(IPv4_TCP_No_Payload_Packet))
+		{
+			LOG_MSG_ERROR("Buffer is smaller than %zu, no Data was copied.",
+				sizeof(IPv4_TCP_No_Payload_Packet));
+			return false;
+		}
+		memcpy(pBuffer, IPv4_TCP_No_Payload_Packet, sizeof(IPv4_TCP_No_Payload_Packet));
+		nMaxSize = sizeof(IPv4_TCP_No_Payload_Packet);
+	} else {
+		if (nMaxSize < sizeof(IPv6_TCP_No_Payload_Packet))
+		{
+			LOG_MSG_ERROR("Buffer is smaller than %zu, no Data was copied.",
+				sizeof(IPv6_TCP_No_Payload_Packet));
+			return false;
+		}
+		memcpy(pBuffer, IPv6_TCP_No_Payload_Packet, sizeof(IPv6_TCP_No_Payload_Packet));
+		nMaxSize = sizeof(IPv6_TCP_No_Payload_Packet);
+	}
+
+	return true;
+}
+
+bool LoadDefaultEth2Packet(
+	enum ipa_ip_type eIP,
+	uint8_t *pBuffer,
+	size_t &nMaxSize)
+{
+	if (IPA_IP_v4 == eIP) {
+		if (nMaxSize < sizeof(Eth2IPv4Packet))
+		{
+			LOG_MSG_ERROR(
+				"Buffer is smaller than %d, "
+				"no data was copied.",
+				sizeof(Eth2IPv4Packet));
+			return false;
+		}
+		memcpy(pBuffer,Eth2IPv4Packet,
+			sizeof(Eth2IPv4Packet));
+		nMaxSize = sizeof(Eth2IPv4Packet);
+	}
+	else
+	{
+		if (nMaxSize < sizeof(Eth2IPv6Packet))
+		{
+			LOG_MSG_ERROR(
+				"Buffer is smaller than %d, "
+				"no data was copied.",
+				sizeof(Eth2IPv6Packet));
+			return false;
+		}
+		memcpy(pBuffer,Eth2IPv6Packet,
+			sizeof(Eth2IPv6Packet));
+		nMaxSize = sizeof(Eth2IPv6Packet);
+	}
+
+	return true;
+}
+
+bool LoadDefaultWLANEth2Packet(
+	enum ipa_ip_type eIP,
+	uint8_t *pBuffer,
+	size_t &nMaxSize)
+{
+	if (IPA_IP_v4 == eIP) {
+		if (nMaxSize < sizeof(WLANEth2IPv4Packet))
+		{
+			LOG_MSG_ERROR(
+				"Buffer is smaller than %d, "
+				"no data was copied.",
+				sizeof(WLANEth2IPv4Packet));
+			return false;
+		}
+		memcpy(pBuffer,WLANEth2IPv4Packet,
+			sizeof(WLANEth2IPv4Packet));
+		nMaxSize = sizeof(WLANEth2IPv4Packet);
+	}
+	else
+	{
+		LOG_MSG_ERROR("%s isn't implemented "
+			"for IPv6 - do it yourself :-)",
+			__FUNCTION__);
+		return false;
+	}
+
+	return true;
+}
+
+bool LoadDefaultWLAN802_32Packet(
+	enum ipa_ip_type eIP,
+	uint8_t *pBuffer,
+	size_t &nMaxSize)
+{
+	if (IPA_IP_v4 == eIP) {
+		if (nMaxSize < sizeof(WLAN802_3IPv4Packet))
+		{
+			LOG_MSG_ERROR(
+				"Buffer is smaller than %d, "
+				"no data was copied.",
+				sizeof(WLAN802_3IPv4Packet));
+			return false;
+		}
+		memcpy(pBuffer,WLAN802_3IPv4Packet,
+			sizeof(WLAN802_3IPv4Packet));
+		nMaxSize = sizeof(WLAN802_3IPv4Packet);
+	}
+	else
+	{
+		LOG_MSG_ERROR("%s isn't implemented"
+			" for IPv6 - do it yourself :-)",
+			__FUNCTION__);
+		return false;
+	}
+
+	return true;
+}
+
+bool LoadDefault802_1Q(
+	enum ipa_ip_type eIP,
+	uint8_t *pBuffer,
+	size_t &nMaxSize)
+{
+	if (IPA_IP_v4 == eIP) {
+		if (nMaxSize < sizeof(Eth2IPv4Packet802_1Q_tag)) {
+			LOG_MSG_ERROR(
+				"Buffer is smaller than %d, "
+				"no data was copied.",
+				sizeof(Eth2IPv4Packet802_1Q_tag));
+			return false;
+		}
+		memcpy(pBuffer, Eth2IPv4Packet802_1Q_tag,
+			sizeof(Eth2IPv4Packet802_1Q_tag));
+		nMaxSize = sizeof(Eth2IPv4Packet802_1Q_tag);
+	} else {
+		LOG_MSG_ERROR("%s isn't implemented"
+			" for IPv6 - do it yourself :-)",
+			__FUNCTION__);
+		return false;
+	}
+
+	return true;
+}
+
+bool SendReceiveAndCompare(InterfaceAbstraction *pSink, uint8_t* pSendBuffer, size_t nSendBuffSize,
+		InterfaceAbstraction *pSource, uint8_t* pExpectedBuffer, size_t nExpectedBuffSize)
+{
+	LOG_MSG_STACK("Entering Function");
+	bool bRetVal = true;
+	uint8_t * pRxBuff = new uint8_t[2*(nExpectedBuffSize+1)];
+	size_t nReceivedBuffSize = 0;
+	size_t j;
+
+	// Send buffer to pSink
+	bRetVal = pSink->SendData((Byte *) pSendBuffer, nSendBuffSize);
+	if (!bRetVal)
+	{
+		LOG_MSG_ERROR("SendData (pOutputBuffer=0x%p) failed",pSendBuffer);
+		goto bail;
+	}
+
+	// Receive buffer from pSource
+	if (NULL == pRxBuff)
+	{
+		LOG_MSG_ERROR("Failed to allocated pRxBuff[%d]",2*(nExpectedBuffSize+1));
+		goto bail;
+	}
+	nReceivedBuffSize = pSource->ReceiveData(pRxBuff, 2*(nExpectedBuffSize+1)); // We cannot overflow here.
+	LOG_MSG_INFO("Received %d bytes on %s.", nReceivedBuffSize, pSource->m_fromChannelName.c_str());
+	if (0 > nReceivedBuffSize)
+	{
+		bRetVal = false;
+		goto bail;
+	}
+
+	{// Logging Expected and Received buffers
+		char aExpectedBufferStr[3*nExpectedBuffSize+1];
+		char aRecievedBufferStr[3*nReceivedBuffSize+1];
+		memset(aExpectedBufferStr,0,3*nExpectedBuffSize+1);
+		memset(aRecievedBufferStr,0,3*nReceivedBuffSize+1);
+
+		for(j = 0; j < nExpectedBuffSize; j++)
+			snprintf(&aExpectedBufferStr[3*j], 3*nExpectedBuffSize+1 - (3*j + 1), " %02X", pExpectedBuffer[j]);
+		for(j = 0; j < nReceivedBuffSize; j++)
+			snprintf(&aRecievedBufferStr[3*j], 3*nReceivedBuffSize+1 - (3*j + 1), " %02X", pRxBuff[j]);
+		LOG_MSG_INFO("\nExpected Value (%d)\n%s\n, Received Value(%d)\n%s\n",nExpectedBuffSize,aExpectedBufferStr,nReceivedBuffSize,aRecievedBufferStr);
+	}
+
+	//Comparing Expected and received sizes
+	if (nExpectedBuffSize != nReceivedBuffSize)
+	{
+		LOG_MSG_INFO("Buffers' Size differ: expected(%d), Received(%d)",nExpectedBuffSize,nReceivedBuffSize);
+		bRetVal = false;
+		goto bail;
+	}
+
+	bRetVal = !memcmp((void*)pRxBuff, (void*)pExpectedBuffer, nExpectedBuffSize);
+	LOG_MSG_INFO("Buffers %s ",bRetVal?"MATCH":"MISMATCH");
+
+
+	LOG_MSG_INFO("Verify that pipe is Empty");
+	nReceivedBuffSize = pSource->ReceiveData(pRxBuff, 2*(nExpectedBuffSize+1)); // We cannot overflow here.
+	while (nReceivedBuffSize){
+		char aRecievedBufferStr[3*nReceivedBuffSize+1];
+		bRetVal = false;
+		LOG_MSG_ERROR("More Data in Pipe!\nReceived %d bytes on %s.", nReceivedBuffSize, pSource->m_fromChannelName.c_str());
+		memset(aRecievedBufferStr,0,3*nReceivedBuffSize+1);
+		for(j = 0; j < nReceivedBuffSize; j++) {
+			snprintf(&aRecievedBufferStr[3*j], 3*nReceivedBuffSize+1 - (3*j + 1), " %02X", pRxBuff[j]);
+		}
+		LOG_MSG_ERROR("\nReceived Value(%d)\n%s\n",nReceivedBuffSize,aRecievedBufferStr);
+		nReceivedBuffSize = pSource->ReceiveData(pRxBuff, 2*(nExpectedBuffSize+1)); // We cannot overflow here.
+	}
+
+bail:
+	delete (pRxBuff);
+	LOG_MSG_STACK("Leaving Function (Returning %s)",bRetVal?"True":"False");
+	return bRetVal;
+}
+
+bool CreateBypassRoutingTable (RoutingDriverWrapper * pRouting,enum ipa_ip_type eIP,
+		const char * pTableName, enum ipa_client_type eRuleDestination,
+		uint32_t uHeaderHandle, uint32_t * pTableHdl)
+{
+	bool bRetVal = true;
+	struct ipa_ioc_add_rt_rule *pRoutingRule = NULL;
+	struct ipa_rt_rule_add *pRoutingRuleEntry = NULL;
+	struct ipa_ioc_get_rt_tbl sRoutingTable;
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sRoutingTable,0,sizeof(sRoutingTable));
+	pRoutingRule = (struct ipa_ioc_add_rt_rule *)
+		calloc(1,
+				sizeof(struct ipa_ioc_add_rt_rule) +
+		       1*sizeof(struct ipa_rt_rule_add)
+			);
+	if(!pRoutingRule) {
+		LOG_MSG_ERROR("calloc failed to allocate pRoutingRule");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pRoutingRule->num_rules = 1;
+	pRoutingRule->ip = ((IPA_IP_v4 == eIP)? IPA_IP_v4 : IPA_IP_v6);
+	pRoutingRule->commit = true;
+	strlcpy(pRoutingRule->rt_tbl_name, pTableName, sizeof(pRoutingRule->rt_tbl_name));
+
+	pRoutingRuleEntry = &(pRoutingRule->rules[0]);
+	pRoutingRuleEntry->at_rear = 1;
+	pRoutingRuleEntry->rule.dst = eRuleDestination;// Setting Rule's Destination Pipe
+	pRoutingRuleEntry->rule.hdr_hdl = uHeaderHandle; // Header handle
+	pRoutingRuleEntry->rule.attrib.attrib_mask = 0;// All Packets will get a "Hit"
+	if (false == pRouting->AddRoutingRule(pRoutingRule))
+	{
+		LOG_MSG_ERROR("Routing rule addition(pRoutingRule) failed!");
+		bRetVal = false;
+		goto bail;
+	}
+	if (!pRoutingRuleEntry->rt_rule_hdl)
+	{
+		LOG_MSG_ERROR("pRoutingRuleEntry->rt_rule_hdl == 0, Routing rule addition(pRoutingRule) failed!");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_INFO("pRoutingRuleEntry->rt_rule_hdl == 0x%x added to Table %s",pRoutingRuleEntry->rt_rule_hdl,pTableName);
+	sRoutingTable.ip = eIP;
+	strlcpy(sRoutingTable.name, pTableName, sizeof(sRoutingTable.name));
+	if (!pRouting->GetRoutingTable(&sRoutingTable)) {
+		LOG_MSG_ERROR(
+				"m_routing.GetRoutingTable(&sRoutingTable=0x%p) Failed.", &sRoutingTable);
+		bRetVal = false;
+		goto bail;
+	}
+	if(NULL != pTableHdl){
+		(* pTableHdl ) = sRoutingTable.hdl;
+		LOG_MSG_DEBUG("Table Handle =0x%x will be returned.",(*pTableHdl));
+	}
+
+bail:
+	Free (pRoutingRule);
+	LOG_MSG_STACK("Leaving Function (Returning %s)",bRetVal?"True":"False");
+	return bRetVal;
+}
+
+bool CreateBypassRoutingTable_v2 (RoutingDriverWrapper * pRouting,enum ipa_ip_type eIP,
+		const char * pTableName, enum ipa_client_type eRuleDestination,
+		uint32_t uHeaderHandle, uint32_t * pTableHdl, uint8_t uClsAggrIrqMod)
+{
+	bool bRetVal = true;
+	struct ipa_ioc_add_rt_rule_v2 *pRoutingRule = NULL;
+	struct ipa_rt_rule_add_v2 *pRoutingRuleEntry = NULL;
+	struct ipa_ioc_get_rt_tbl sRoutingTable;
+
+	LOG_MSG_STACK("Entering Function");
+	memset(&sRoutingTable,0,sizeof(sRoutingTable));
+	pRoutingRule = (struct ipa_ioc_add_rt_rule_v2 *)
+		calloc(1, sizeof(struct ipa_ioc_add_rt_rule_v2));
+	if(!pRoutingRule) {
+		LOG_MSG_ERROR("calloc failed to allocate pRoutingRule");
+		bRetVal = false;
+		goto bail;
+	}
+	pRoutingRule->rules = (uint64_t)calloc(1, sizeof(struct ipa_rt_rule_add_v2));
+	if (!pRoutingRule->rules) {
+		LOG_MSG_ERROR("calloc failed to allocate pRoutingRule->rules");
+		bRetVal = false;
+		goto bail;
+	}
+
+	pRoutingRule->num_rules = 1;
+	pRoutingRule->rule_add_size = sizeof(struct ipa_rt_rule_add_v2);
+	printf("%s(), Nadav: Adding rule_add_size\n", __FUNCTION__);
+	pRoutingRule->ip = ((IPA_IP_v4 == eIP)? IPA_IP_v4 : IPA_IP_v6);
+	pRoutingRule->commit = true;
+	strlcpy(pRoutingRule->rt_tbl_name, pTableName, sizeof(pRoutingRule->rt_tbl_name));
+
+	pRoutingRuleEntry = &(((struct ipa_rt_rule_add_v2 *)pRoutingRule->rules)[0]);
+	pRoutingRuleEntry->at_rear = 1;
+	pRoutingRuleEntry->rule.dst = eRuleDestination;// Setting Rule's Destination Pipe
+	printf("%s(), Nadav: Destination = %d\n", __FUNCTION__, pRoutingRuleEntry->rule.dst);
+	pRoutingRuleEntry->rule.hdr_hdl = uHeaderHandle; // Header handle
+	pRoutingRuleEntry->rule.attrib.attrib_mask = 0;// All Packets will get a "Hit"
+	pRoutingRuleEntry->rule.close_aggr_irq_mod = uClsAggrIrqMod;
+	if (false == pRouting->AddRoutingRule(pRoutingRule))
+	{
+		LOG_MSG_ERROR("Routing rule addition(pRoutingRule) failed!");
+		bRetVal = false;
+		goto bail;
+	}
+	if (!pRoutingRuleEntry->rt_rule_hdl)
+	{
+		LOG_MSG_ERROR("pRoutingRuleEntry->rt_rule_hdl == 0, Routing rule addition(pRoutingRule) failed!");
+		bRetVal = false;
+		goto bail;
+	}
+	LOG_MSG_INFO("pRoutingRuleEntry->rt_rule_hdl == 0x%x added to Table %s",pRoutingRuleEntry->rt_rule_hdl,pTableName);
+	sRoutingTable.ip = eIP;
+	strlcpy(sRoutingTable.name, pTableName, sizeof(sRoutingTable.name));
+	if (!pRouting->GetRoutingTable(&sRoutingTable)) {
+		LOG_MSG_ERROR(
+				"m_routing.GetRoutingTable(&sRoutingTable=0x%p) Failed.", &sRoutingTable);
+		bRetVal = false;
+		goto bail;
+	}
+	if(NULL != pTableHdl){
+		(* pTableHdl ) = sRoutingTable.hdl;
+		LOG_MSG_DEBUG("Table Handle =0x%x will be returned.",(*pTableHdl));
+	}
+
+bail:
+	Free (pRoutingRule);
+	LOG_MSG_STACK("Leaving Function (Returning %s)",bRetVal?"True":"False");
+	return bRetVal;
+}
+
+//Don't use these methods directly. use MACROs instead
+void __log_msg(enum msgType logType, const char* filename, int line, const char* function, const char* format, ... )
+{
+	va_list args;
+	switch (logType) {
+	case ERROR:
+		fprintf( stderr, "ERROR!");
+		break;
+	case DEBUG:
+		fprintf( stderr, "DEBUG:");
+		break;
+	case INFO:
+		fprintf( stderr, "INFO :");
+		break;
+	case STACK:
+		fprintf( stderr, "STACK:");
+		break;
+	default:
+		fprintf( stderr, "BUG!!!");
+		break;
+	}
+	fprintf( stderr, " [%s:%d, %s()] ",filename,line,function);
+	va_start( args, format );
+	vfprintf( stderr, format, args );
+	va_end( args );
+	fprintf( stderr, "\n" );
+}
+
+bool file_exists(const char* filename)
+{
+	return (access(filename, F_OK) == 0);
+}
+
+int ConfigureSystem(int testConfiguration, int fd)
+{
+	return ConfigureSystem(testConfiguration, fd, NULL);
+}
+
+int ConfigureSystem(int testConfiguration, int fd, const char* params)
+{
+	char testConfigurationStr[10];
+	int ret;
+	char *pSendBuffer;
+	char str[10];
+	int iter_cnt = 2000;
+
+	if(params != NULL)
+		pSendBuffer = new char[strlen(params) + 10];
+	else
+		pSendBuffer = new char[10];
+
+	if (NULL == pSendBuffer)
+	{
+		LOG_MSG_ERROR("Failed to allocated pSendBuffer");
+		return -1;
+	}
+
+	if(params != NULL)
+		snprintf(pSendBuffer, strlen(params) + 10, "%d %s", testConfiguration, params);
+	else
+		snprintf(pSendBuffer, 10, "%d", testConfiguration);
+
+	ret = write(fd, pSendBuffer, sizeof(pSendBuffer) );
+	if (ret < 0) {
+		g_Logger.AddMessage(LOG_ERROR, "%s Write operation failed.\n", __FUNCTION__);
+		goto bail;
+	}
+
+	// Wait until the system is fully configured
+
+	// Convert testConfiguration to string
+	snprintf(testConfigurationStr, sizeof(testConfigurationStr), "%d", testConfiguration);
+
+	// Read the configuration index from the device node
+	ret = read(fd, str, sizeof(str));
+	if (ret < 0) {
+		g_Logger.AddMessage(LOG_ERROR, "%s Read operation failed.\n", __FUNCTION__);
+		goto bail;
+	}
+
+	while ( strcmp(str, testConfigurationStr) ) {
+		// Sleep for 5 msec
+		struct timespec time;
+		time.tv_sec = 0;
+		time.tv_nsec = 50e6;
+		nanosleep(&time, NULL);
+		ret = read(fd, str, sizeof(str));
+		if (ret < 0) {
+			g_Logger.AddMessage(LOG_ERROR, "%s Read operation failed.\n", __FUNCTION__);
+			goto bail;
+		}
+		if (!--iter_cnt) {
+			g_Logger.AddMessage(LOG_ERROR, "%s timeout waiting for test driver.\n", __FUNCTION__);
+			ret = -1;
+			goto bail;
+		}
+	}
+bail:
+	delete[] pSendBuffer;
+	return ret;
+}
+
+void ConfigureScenario(int testConfiguration)
+{
+	ConfigureScenario(testConfiguration, NULL);
+}
+
+void ConfigureScenario(int testConfiguration, const char* params)
+{
+	int fd, ret;
+	char str[10];
+	int currentConf;
+
+	// Open /dev/ipa_test device node. This will allow to configure the system
+	// and read its current configuration.
+	fd = open(CONFIGURATION_NODE_PATH, O_RDWR);
+	if (fd < 0) {
+		g_Logger.AddMessage(LOG_ERROR, "%s Could not open configuration device node.\n", __FUNCTION__);
+		exit(0);
+	}
+
+	// Read the current configuration.
+	ret = read(fd, str, sizeof(str));
+	if (ret < 0) {
+		g_Logger.AddMessage(LOG_ERROR, "%s Read operation failed.\n", __FUNCTION__);
+		return;
+	}
+	currentConf = atoi(str);
+
+	// Do not reconfigure to the same configuration
+	if (currentConf == testConfiguration) {
+		g_Logger.AddMessage(LOG_DEVELOPMENT,"%s System was already configured as required(%d)\n",
+			__FUNCTION__, currentConf);
+		return;
+	}
+
+	/* in case the system is not "clean"*/
+	if (-1 != currentConf) {
+		g_Logger.AddMessage(LOG_DEVELOPMENT,"%s System has other configuration (%d) - cleanup\n", __FUNCTION__, currentConf);
+		ret = ConfigureSystem(-1, fd);
+		if (ret < 0) {
+			g_Logger.AddMessage(LOG_ERROR, "%s Configure operation failed.\n",
+					__FUNCTION__);
+			return;
+		}
+	}
+
+	// Start system configuration.
+	g_Logger.AddMessage(LOG_DEVELOPMENT,"%s Setting system to the required configuration (%d)\n", __FUNCTION__, testConfiguration);
+
+	ret = ConfigureSystem(testConfiguration, fd, params);
+	if (ret < 0) {
+		g_Logger.AddMessage(LOG_ERROR, "%s configure operation failed.\n",
+				__FUNCTION__);
+		return;
+	}
+
+	ret = system("mdev -s");
+	if (ret < 0) {
+		g_Logger.AddMessage(LOG_ERROR, "%s system(\"mdev -s\") returned %d\n",
+				__FUNCTION__, ret);
+	}
+
+	close(fd);
+}//func
+
+void clean_old_stashed_config()
+{
+	if (current_configuration == NULL)
+		return;
+
+	for (int i = 0 ; i < current_configuration->from_ipa_channels_num ; i++) {
+		delete((struct test_ipa_ep_cfg*)
+				current_configuration->from_ipa_channel_config[i]->cfg);
+		delete((struct test_ipa_ep_cfg*)
+				current_configuration->from_ipa_channel_config[i]);
+	}
+
+	for (int i = 0 ; i < current_configuration->to_ipa_channels_num ; i++) {
+		delete((struct test_ipa_ep_cfg*)
+				current_configuration->to_ipa_channel_config[i]->cfg);
+		delete((struct test_ipa_ep_cfg*)
+				current_configuration->to_ipa_channel_config[i]);
+	}
+	delete(current_configuration);
+	current_configuration = NULL;
+}
+
+void stash_new_configuration(struct ipa_test_config_header *header)
+{
+	clean_old_stashed_config();
+
+        /*
+	 * We will start by shallow copying each level, and afterwards,
+	 * override the pointers
+	 */
+		current_configuration = new ipa_test_config_header();
+		*current_configuration = *header;
+
+		current_configuration->from_ipa_channel_config =
+			new ipa_channel_config*[header->from_ipa_channels_num]();
+
+		current_configuration->to_ipa_channel_config =
+			new ipa_channel_config*[header->to_ipa_channels_num]();
+
+		for (int i = 0 ; i < current_configuration->from_ipa_channels_num ; i++) {
+			current_configuration->from_ipa_channel_config[i] =
+				new ipa_channel_config;
+			*current_configuration->from_ipa_channel_config[i] =
+				*header->from_ipa_channel_config[i];
+			current_configuration->from_ipa_channel_config[i]->cfg =
+				new test_ipa_ep_cfg();
+			memcpy(current_configuration->from_ipa_channel_config[i]->cfg,
+				header->from_ipa_channel_config[i]->cfg,
+				header->from_ipa_channel_config[i]->config_size);
+		}
+
+		for (int i = 0 ; i < current_configuration->to_ipa_channels_num ; i++) {
+			current_configuration->to_ipa_channel_config[i] =
+				new ipa_channel_config;
+			*current_configuration->to_ipa_channel_config[i] =
+				*header->to_ipa_channel_config[i];
+			current_configuration->to_ipa_channel_config[i]->cfg = new test_ipa_ep_cfg();
+			memcpy(current_configuration->to_ipa_channel_config[i]->cfg,
+				header->to_ipa_channel_config[i]->cfg,
+				header->to_ipa_channel_config[i]->config_size);
+		}
+}
+
+bool is_prev_configuration_generic()
+{
+	int fd;
+	char str[10] = {0};
+	int retval;
+	int current_conf_num;
+
+	fd = open(CONFIGURATION_NODE_PATH, O_RDWR);
+	if (fd < 0) {
+		g_Logger.AddMessage(LOG_ERROR ,"%s Could not open configuration device node.\n", __FUNCTION__);
+		exit(0);
+	}
+
+	retval = read(fd, str, sizeof(str));
+	close(fd);
+	if (retval < 0) {
+		g_Logger.AddMessage(LOG_ERROR ,"%s Read operation failed.\n", __FUNCTION__);
+		return true;
+	}
+	current_conf_num = atoi(str);
+
+	if (current_conf_num == GENERIC_TEST_CONFIGURATION_IDX)
+		return true;
+
+	return false;
+}
+
+
+static bool is_reconfigure_required(struct ipa_test_config_header *header)
+{
+	// Is reconfiguration not required flag (current conf is cool)
+	bool flag = true;
+
+	if (is_prev_configuration_generic() == false) {
+		g_Logger.AddMessage(LOG_DEVELOPMENT ,
+			"prev configuration didn't use generic configuration\n");
+		return true;
+	}
+
+	if (current_configuration == NULL) {
+		g_Logger.AddMessage(LOG_DEVELOPMENT ,
+			"no prev generic configuration found in the test app data-base\n");
+		return true;
+	}
+
+	flag &= (header->from_ipa_channels_num ==
+			current_configuration->from_ipa_channels_num);
+	flag &= (header->to_ipa_channels_num ==
+			current_configuration->to_ipa_channels_num);
+
+	if (flag == false) {
+		g_Logger.AddMessage(LOG_DEVELOPMENT ,
+			"not same number of pipes\n");
+		return true;
+	}
+
+	for (int i = 0 ; i < header->from_ipa_channels_num ; i++) {
+		flag &= (header->from_ipa_channel_config[i]->client ==
+				current_configuration->from_ipa_channel_config[i]->client);
+		flag &= (header->from_ipa_channel_config[i]->index ==
+				current_configuration->from_ipa_channel_config[i]->index);
+		flag &= !memcmp(header->from_ipa_channel_config[i]->cfg,
+				current_configuration->from_ipa_channel_config[i]->cfg,
+				header->from_ipa_channel_config[i]->config_size);
+		flag &= (header->from_ipa_channel_config[i]->en_status ==
+				current_configuration->from_ipa_channel_config[i]->en_status);
+	}
+
+	if (flag == false) {
+		g_Logger.AddMessage(LOG_DEVELOPMENT ,
+			"\"from\" endpoint configuration is different from prev\n");
+		return true;
+	}
+
+	for (int i = 0 ; i < header->to_ipa_channels_num ; i++) {
+		flag &= (header->to_ipa_channel_config[i]->client ==
+				current_configuration->to_ipa_channel_config[i]->client);
+		flag &= (header->to_ipa_channel_config[i]->index ==
+				current_configuration->to_ipa_channel_config[i]->index);
+		flag &= !memcmp(header->to_ipa_channel_config[i]->cfg,
+				current_configuration->to_ipa_channel_config[i]->cfg,
+				header->to_ipa_channel_config[i]->config_size);
+		flag &= (header->to_ipa_channel_config[i]->en_status ==
+				current_configuration->to_ipa_channel_config[i]->en_status);
+	}
+
+	if (flag == false) {
+		g_Logger.AddMessage(LOG_DEVELOPMENT ,
+			"\"to\" endpoint configuration is different from prev\n");
+		return true;
+	}
+
+	return false;
+}
+
+int GenericConfigureScenario(struct ipa_test_config_header *header)
+{
+	int fd;
+	int retval;
+
+	if (is_reconfigure_required(header) == false) {
+		g_Logger.AddMessage(LOG_DEVELOPMENT ,
+			"No need to reconfigure, we are all good :)\n");
+		return true;
+	} else {
+		g_Logger.AddMessage(LOG_DEVELOPMENT ,
+			"Need to run configuration again\n");
+	}
+	g_Logger.AddMessage(LOG_DEVELOPMENT, "configuration has started, parameters:\n");
+	g_Logger.AddMessage(LOG_DEVELOPMENT, "header->head_marker=0x%x\n", header->head_marker);
+	g_Logger.AddMessage(LOG_DEVELOPMENT, "header->from_ipa_channels_num=%d\n", header->from_ipa_channels_num);
+	g_Logger.AddMessage(LOG_DEVELOPMENT, "header->to_ipa_channels_num=%d\n", header->to_ipa_channels_num);
+	g_Logger.AddMessage(LOG_DEVELOPMENT, "header->tail_marker=0x%x\n", header->tail_marker);
+
+	for (int i = 0 ; i < header->from_ipa_channels_num ; i++) {
+		g_Logger.AddMessage(LOG_DEVELOPMENT,
+				"header->from_ipa_channel_config[%d]->head_marker=0x%x\n", i,
+				header->from_ipa_channel_config[i]->head_marker);
+		g_Logger.AddMessage(LOG_DEVELOPMENT,
+				"header->from_ipa_channel_config[%d]->index=%d\n", i,
+				header->from_ipa_channel_config[i]->index);
+		g_Logger.AddMessage(LOG_DEVELOPMENT,
+				"header->from_ipa_channel_config[%d]->client=%d\n", i,
+				header->from_ipa_channel_config[i]->client);
+		g_Logger.AddMessage(LOG_DEVELOPMENT,
+				"header->from_ipa_channel_config[%d]->config_size=%d\n", i,
+				header->from_ipa_channel_config[i]->config_size);
+		g_Logger.AddMessage(LOG_DEVELOPMENT,
+				"header->from_ipa_channel_config[%d]->en_status=%d\n", i,
+				header->from_ipa_channel_config[i]->en_status);
+	}
+
+	for (int i = 0 ; i < header->to_ipa_channels_num ; i++) {
+		g_Logger.AddMessage(LOG_DEVELOPMENT,
+			"header->to_ipa_channel_config[%d]->head_marker=0x%x\n", i,
+			header->to_ipa_channel_config[i]->head_marker);
+		g_Logger.AddMessage(LOG_DEVELOPMENT,
+			"header->to_ipa_channel_config[%d]->index=%d\n", i,
+			header->to_ipa_channel_config[i]->index);
+		g_Logger.AddMessage(LOG_DEVELOPMENT,
+			"header->to_ipa_channel_config[%d]->client=%d\n", i,
+			header->to_ipa_channel_config[i]->client);
+		g_Logger.AddMessage(LOG_DEVELOPMENT,
+			"header->to_ipa_channel_config[%d]->config_size=%d\n", i,
+			header->to_ipa_channel_config[i]->config_size);
+		g_Logger.AddMessage(LOG_DEVELOPMENT,
+				"header->to_ipa_channel_config[%d]->en_status=%d\n", i,
+				header->to_ipa_channel_config[i]->en_status);
+	}
+
+	fd = open(CONFIGURATION_NODE_PATH,  O_RDWR);
+	if (fd == -1) {
+		g_Logger.AddMessage(LOG_ERROR,
+				"%s - open %s failed (fd=%d,errno=%s)\n",
+				__FUNCTION__, CONFIGURATION_NODE_PATH, fd, strerror(errno));
+		return false;
+	}
+
+	retval = ioctl(fd, IPA_TEST_IOC_CONFIGURE, header);
+	if (retval) {
+		g_Logger.AddMessage(LOG_ERROR, "fail to configure the system (%d)\n", retval);
+		close(fd);
+		return false;
+	} else {
+		g_Logger.AddMessage(LOG_DEVELOPMENT, "system was successfully configured\n");
+	}
+
+	retval = close(fd);
+	if (retval) {
+		g_Logger.AddMessage(LOG_ERROR,
+				"%s - fail to close the fd (path=%s,retval=%d,fd=%d,errno=%s)\n",
+				__FUNCTION__, CONFIGURATION_NODE_PATH, retval, fd, strerror(errno));
+		return false;
+	}
+
+	g_Logger.AddMessage(LOG_DEVELOPMENT ,"stashing new configuration\n");
+	stash_new_configuration(header);
+
+	g_Logger.AddMessage(LOG_DEVELOPMENT,
+			"Running mdev in order to create the device nodes.\n");
+
+	retval = system("mdev -s");
+	if (retval < 0) {
+		g_Logger.AddMessage(LOG_ERROR, "%s system(\"mdev -s\") returned %d\n",
+				__FUNCTION__, retval);
+	}
+
+	return true;
+}
+
+int GenericConfigureScenarioDestory(void)
+{
+	int fd;
+	int retval;
+
+	g_Logger.AddMessage(LOG_DEVELOPMENT, "cleanup started\n");
+
+	fd = open(CONFIGURATION_NODE_PATH,  O_RDWR);
+	if (fd == -1) {
+		g_Logger.AddMessage(LOG_ERROR,
+			"%s - open %s failed (retval=%d,fd=%d,errno=%s)\n",
+			__FUNCTION__, CONFIGURATION_NODE_PATH, fd, strerror(errno));
+		return false;
+	}
+
+	retval = ioctl(fd, IPA_TEST_IOC_CLEAN);
+	if (retval)
+		g_Logger.AddMessage(LOG_ERROR, "fail to clean the system (%d)\n", retval);
+	else
+		g_Logger.AddMessage(LOG_DEVELOPMENT, "system was successfully cleaned\n");
+
+	retval = close(fd);
+	if (retval) {
+		g_Logger.AddMessage(LOG_ERROR, "fail to close the fd - %d\n", retval);
+		return false;
+	}
+
+	return true;
+}
+
+bool configure_ep_ctrl(struct ipa_test_ep_ctrl *ep_ctrl)
+{
+	int fd;
+	int retval = 0;
+
+	g_Logger.AddMessage(LOG_DEVELOPMENT, "ep ctrl started \n");
+
+	fd = open(CONFIGURATION_NODE_PATH,  O_RDWR);
+	if (fd == -1) {
+		g_Logger.AddMessage(LOG_ERROR,
+			"%s - open %s failed (retval=%d,fd=%d,errno=%s)\n",
+			__FUNCTION__, CONFIGURATION_NODE_PATH, fd, strerror(errno));
+		return false;
+	}
+
+	retval = ioctl(fd, IPA_TEST_IOC_EP_CTRL, ep_ctrl);
+	if (retval)
+		g_Logger.AddMessage(LOG_ERROR, "fail to perform ep ctrl (%d)\n", retval);
+	else
+		g_Logger.AddMessage(LOG_DEVELOPMENT, "ep ctrl was successfully executed\n");
+
+	retval = close(fd);
+	if (retval) {
+		g_Logger.AddMessage(LOG_ERROR, "fail to close the fd - %d\n", retval);
+	}
+
+	return true;
+}
+
+bool configure_holb(struct ipa_test_holb_config *test_holb_config)
+{
+	int fd;
+	int retval = 0;
+
+	g_Logger.AddMessage(LOG_DEVELOPMENT, "holb config started \n");
+
+	if (!test_holb_config) {
+		g_Logger.AddMessage(LOG_ERROR, "Null pointer argument!");
+		return false;
+	}
+
+	fd = open(CONFIGURATION_NODE_PATH,  O_RDWR);
+	if (fd == -1) {
+		g_Logger.AddMessage(LOG_ERROR,
+			"%s - open %s failed (retval=%d,fd=%d,errno=%s)\n",
+			__FUNCTION__, CONFIGURATION_NODE_PATH, fd, strerror(errno));
+		return false;
+	}
+
+	retval = ioctl(fd, IPA_TEST_IOC_HOLB_CONFIG, test_holb_config);
+	if (retval)
+		g_Logger.AddMessage(LOG_ERROR,
+							"fail to perform holb config (%d)\n",
+							retval);
+	else
+		g_Logger.AddMessage(LOG_DEVELOPMENT,
+							"holb config was successfully executed\n");
+
+	retval = close(fd);
+	if (retval) {
+		g_Logger.AddMessage(LOG_ERROR, "fail to close the fd - %d\n", retval);
+	}
+
+	return true;
+}
+
+void prepare_channel_struct(struct ipa_channel_config *channel,
+		int index,
+		enum ipa_client_type client,
+		void *cfg,
+		size_t config_size,
+		bool en_status)
+{
+	channel->head_marker = IPA_TEST_CHANNEL_CONFIG_MARKER;
+	channel->index = index;
+	channel->client = client;
+	channel->cfg = (char*)cfg;
+	channel->config_size = config_size;
+	channel->tail_marker = IPA_TEST_CHANNEL_CONFIG_MARKER;
+	channel->en_status = en_status;
+}
+
+void prepare_header_struct(struct ipa_test_config_header *header,
+		struct ipa_channel_config **from,
+		struct ipa_channel_config **to)
+{
+	header->head_marker = IPA_TEST_CONFIG_MARKER;
+	header->from_ipa_channel_config = from;
+	header->to_ipa_channel_config = to;
+	header->tail_marker = IPA_TEST_CONFIG_MARKER;
+}
+
+bool CompareResultVsGolden(Byte *goldenBuffer,   unsigned int goldenSize,
+			   Byte *receivedBuffer, unsigned int receivedSize)
+{
+	if (receivedSize != goldenSize) {
+		g_Logger.AddMessage(LOG_VERBOSE,  "%s File sizes are different.\n", __FUNCTION__);
+		return false;
+	}
+	return !memcmp((void*)receivedBuffer, (void*)goldenBuffer, goldenSize);
+}
+
+bool CompareResultVsGolden_w_Status(Byte *goldenBuffer,   unsigned int goldenSize,
+			   Byte *receivedBuffer, unsigned int receivedSize)
+{
+	size_t stts_size = sizeof(struct ipa3_hw_pkt_status);
+
+	if (TestManager::GetInstance()->GetIPAHwType() >= IPA_HW_v5_0) {
+		stts_size = sizeof(struct ipa3_hw_pkt_status_hw_v5_0);
+	}
+
+	if ((receivedSize - stts_size) != goldenSize) {
+		g_Logger.AddMessage(LOG_VERBOSE,  "%s Buffer sizes are different.\n", __FUNCTION__);
+		return false;
+	}
+
+	printf("comparison is made considering %zu status bytes!\n", stts_size);
+
+	return !memcmp((void*)((unsigned char *)receivedBuffer +
+		stts_size), (void*)goldenBuffer, goldenSize);
+}
+
+
+Byte *LoadFileToMemory(const string &name, unsigned int *sizeLoaded)
+{
+	FILE *file;
+	Byte *buffer;
+	size_t fileLen;
+
+	// Open file
+	file = fopen(name.c_str(), "rb");
+	if (!file) {
+		g_Logger.AddMessage(LOG_ERROR,  "Unable to open file %s\n", name.c_str());
+		return NULL;
+	}
+
+	// Get file length
+	fseek(file, 0, SEEK_END);
+	fileLen = ftell(file);
+	fseek(file, 0, SEEK_SET);
+
+	// Allocate memory
+	buffer=(Byte*)malloc(fileLen+1);
+	if (!buffer) {
+		fprintf(stderr, "Memory error!\n");
+		fclose(file);
+		return NULL;
+	}
+
+	// Read file contents into buffer
+	*sizeLoaded = fread(buffer, 1, fileLen, file);
+	fclose(file);
+
+	return buffer;
+}
+
+void print_buff(void *data, size_t size)
+{
+	uint8_t bytes_in_line = 16;
+	uint i, j, num_lines;
+	char str[1024], tmp[4];
+
+	num_lines = size / bytes_in_line;
+	if (size % bytes_in_line > 0)
+		num_lines++;
+
+	printf("Printing buffer at address 0x%p, size = %zu: \n", data, size);
+	for (i = 0 ; i < num_lines; i++) {
+		str[0] = '\0';
+		for (j = 0; (j < bytes_in_line) && ((i * bytes_in_line + j) < size); j++) {
+			snprintf(tmp, sizeof(tmp), "%02x ",
+				 ((unsigned char*)data)[i * bytes_in_line + j]);
+			strlcpy(str + strlen(str), tmp, sizeof(str) - strlen(str));
+		}
+		printf("%s\n", str);
+	}
+}
+
+void add_buff(uint8_t *data, size_t size, uint8_t val)
+{
+	for (int i = 0; i < static_cast<int>(size); i++)
+		data[i]+=val;
+}
+
+bool RegSuspendHandler(bool deferred_flag, bool reg, int DevNum)
+{
+	int fd = 0;
+	int retval = 0;
+	struct ipa_test_reg_suspend_handler RegData;
+
+	fd = open(CONFIGURATION_NODE_PATH,  O_RDWR);
+	if (fd == -1) {
+		g_Logger.AddMessage(LOG_ERROR,
+				"%s - open %s failed (fd=%d,errno=%s)\n",
+				__FUNCTION__, CONFIGURATION_NODE_PATH, fd, strerror(errno));
+		return false;
+	}
+
+	RegData.DevNum = DevNum;
+	RegData.reg = reg;
+	RegData.deferred_flag = deferred_flag;
+
+	retval = ioctl(fd, IPA_TEST_IOC_REG_SUSPEND_HNDL, &RegData);
+	if (retval) {
+		g_Logger.AddMessage(LOG_ERROR, "fail to reg suspend handler (%d)\n", retval);
+		close(fd);
+		return false;
+	} else {
+		g_Logger.AddMessage(LOG_DEVELOPMENT, "suspend handler was successfully configured\n");
+	}
+
+	close(fd);
+
+	return true;
+}
+
+const Byte Eth2Helper::m_ETH2_IP4_HDR[ETH_HLEN] =
+{
+	0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,	// ETH2 DST
+	0xA7, 0xA8, 0xA9, 0xB0, 0xB1, 0xB2,	// ETH2 SRC
+	0x08, 0x00,	// ETH2 TYPE IPv4 - ETH_P_IP 0x0800
+};
+
+bool Eth2Helper::LoadEth2IP4Header(
+	uint8_t *pBuffer,
+	size_t bufferSize,
+	size_t *pLen)
+{
+	if (bufferSize < ETH_HLEN)
+	{
+		LOG_MSG_ERROR("Buffer too small\n");
+		return false;
+	}
+
+	memcpy(pBuffer, m_ETH2_IP4_HDR, ETH_HLEN);
+
+	*pLen = ETH_HLEN;
+
+	return true;
+}
+
+bool Eth2Helper::LoadEth2IP6Header(
+	uint8_t *pBuffer,
+	size_t bufferSize,
+	size_t *pLen)
+{
+	if (bufferSize < ETH_HLEN)
+	{
+		LOG_MSG_ERROR("Buffer too small\n");
+		return false;
+	}
+
+	// copy eth2 ip4 header
+	memcpy(pBuffer, m_ETH2_IP4_HDR, ETH_HLEN);
+
+	// change ethtype to ip6
+	pBuffer[ETH2_ETH_TYPE_OFFSET] = 0x86;
+	pBuffer[ETH2_ETH_TYPE_OFFSET+1] = 0xdd;
+
+	*pLen = ETH_HLEN;
+
+	return true;
+}
+
+bool Eth2Helper::LoadEth2IP4Packet(
+	uint8_t *pBuffer,
+	size_t bufferSize,
+	size_t *pLen)
+{
+	size_t cnt = 0;
+	size_t len = 0;
+
+	if (!LoadEth2IP4Header(pBuffer, bufferSize, &cnt))
+		return false;
+
+	len = bufferSize - cnt;
+
+	if (!LoadDefaultPacket(IPA_IP_v4, pBuffer + cnt, len))
+		return false;
+
+	*pLen = len + cnt;
+
+	return true;
+}
+
+bool Eth2Helper::LoadEth2IP6Packet(
+	uint8_t *pBuffer,
+	size_t bufferSize,
+	size_t *pLen)
+{
+	size_t cnt = 0;
+	size_t len = 0;
+
+	if (!LoadEth2IP6Header(pBuffer, bufferSize, &cnt))
+		return false;
+
+	len = bufferSize - cnt;
+
+	if (!LoadDefaultPacket(IPA_IP_v6, pBuffer + cnt, len))
+		return false;
+
+	*pLen = len + cnt;
+
+	return true;
+}
+
+const Byte WlanHelper::m_WLAN_HDR[WLAN_HDR_SIZE] =
+{
+	// WLAN hdr - 4 bytes
+	0x01, 0x02, 0x03, 0x04
+};
+
+bool WlanHelper::LoadWlanHeader(
+	uint8_t *pBuffer,
+	size_t bufferSize,
+	size_t *pLen)
+{
+	if (bufferSize < WLAN_HDR_SIZE)
+	{
+		LOG_MSG_ERROR("Buffer too small\n");
+		return false;
+	}
+
+	memcpy(pBuffer, m_WLAN_HDR, WLAN_HDR_SIZE);
+
+	*pLen = WLAN_HDR_SIZE;
+
+	return true;
+}
+
+bool WlanHelper::LoadWlanEth2IP4Header(
+	uint8_t *pBuffer,
+	size_t bufferSize,
+	size_t *pLen)
+{
+	size_t cnt = 0;
+	size_t len = 0;
+
+	if (!LoadWlanHeader(pBuffer, bufferSize, &cnt))
+		return false;
+
+	if (!Eth2Helper::LoadEth2IP4Header(
+		pBuffer + cnt,
+		bufferSize - cnt,
+		&len))
+		return false;
+
+	*pLen = len + cnt;
+
+	return true;
+}
+
+bool WlanHelper::LoadWlanEth2IP6Header(
+	uint8_t *pBuffer,
+	size_t bufferSize,
+	size_t *pLen)
+{
+	size_t cnt = 0;
+	size_t len = 0;
+
+	if (!LoadWlanHeader(pBuffer, bufferSize, &cnt))
+		return false;
+
+	if (!Eth2Helper::LoadEth2IP6Header(
+		pBuffer + cnt,
+		bufferSize - cnt,
+		&len))
+		return false;
+
+	*pLen = len + cnt;
+
+	return true;
+}
+
+bool WlanHelper::LoadWlanEth2IP4Packet(
+	uint8_t *pBuffer,
+	size_t bufferSize,
+	size_t *pLen)
+{
+	size_t cnt = 0;
+	size_t len = 0;
+
+	if (!LoadWlanHeader(pBuffer, bufferSize, &cnt))
+		return false;
+
+	if (!Eth2Helper::LoadEth2IP4Packet(
+		pBuffer + cnt,
+		bufferSize - cnt,
+		&len))
+		return false;
+
+	*pLen = len + cnt;
+
+	return true;
+}
+
+bool PadByLength(
+	uint8_t *pBuffer,
+	size_t bufferSize,
+	size_t len,
+	uint8_t padValue)
+{
+	if (bufferSize < len)
+	{
+		LOG_MSG_ERROR("bufferSize < len.\n");
+		return false;
+	}
+
+	memset(pBuffer, padValue, len);
+
+	return true;
+}
+
+bool WlanHelper::LoadWlanEth2IP4PacketByLength(
+	uint8_t *pBuffer,
+	size_t bufferSize,
+	size_t len,
+	uint8_t padValue)
+{
+	size_t cnt = 0;
+
+	if (!LoadWlanEth2IP4Packet(pBuffer, bufferSize, &cnt))
+		return false;
+
+	if (!PadByLength(pBuffer + cnt, bufferSize - cnt, len - cnt, padValue))
+		return false;
+
+	return true;
+}
+
+bool RNDISAggregationHelper::LoadRNDISHeader(
+	uint8_t *pBuffer,
+	size_t bufferSize,
+	uint32_t messageLength,
+	size_t *pLen)
+{
+	if (bufferSize < RNDIS_HDR_SIZE)
+	{
+		LOG_MSG_ERROR("Buffer too small\n");
+		return false;
+	}
+
+	struct RndisHeader *pRndisHeader =
+		reinterpret_cast<struct RndisHeader*>(pBuffer);
+
+	memset(pRndisHeader, 0, sizeof(struct RndisHeader));
+	pRndisHeader->MessageType = 0x01;
+	pRndisHeader->DataOffset = 0x24;
+
+	if (messageLength > RNDIS_HDR_SIZE)
+	{
+		pRndisHeader->MessageLength = messageLength;
+		pRndisHeader->DataLength = messageLength - RNDIS_HDR_SIZE;
+	}
+	else
+	{
+		// This handles a case where we use the header
+		// in IPA headers table
+		// IPA needs to set these values
+		pRndisHeader->MessageLength = 0;
+		pRndisHeader->DataLength = 0;
+	}
+
+	*pLen = RNDIS_HDR_SIZE;
+
+	return true;
+}
+
+bool RNDISAggregationHelper::LoadRNDISEth2IP4Header(
+	uint8_t *pBuffer,
+	size_t bufferSize,
+	uint32_t messageLength,
+	size_t *pLen)
+{
+	size_t cnt = 0;
+	size_t len = 0;
+
+	if (!LoadRNDISHeader(pBuffer, bufferSize, messageLength, &cnt))
+		return 0;
+
+	if (!Eth2Helper::LoadEth2IP4Header(pBuffer + cnt, bufferSize - cnt, &len))
+		return false;
+
+	*pLen = cnt + len;
+
+	return true;
+}
+
+bool RNDISAggregationHelper::LoadRNDISPacket(
+	enum ipa_ip_type eIP,
+	uint8_t *pBuffer,
+	size_t &nMaxSize)
+{
+	if (nMaxSize < sizeof(struct RndisHeader))
+	{
+		LOG_MSG_ERROR("Buffer too small\n");
+		return false;
+	}
+
+	size_t nMaxSizeForDefaultPacket = nMaxSize - sizeof(struct RndisHeader);
+
+	if (!LoadEtherPacket(eIP, pBuffer + sizeof(struct RndisHeader),
+		nMaxSizeForDefaultPacket))
+	{
+		LOG_MSG_ERROR("LoadEtherPacket() failed\n");
+		return false;
+	}
+
+	nMaxSize = nMaxSizeForDefaultPacket + sizeof(struct RndisHeader);
+	struct RndisHeader *pRndisHeader = (struct RndisHeader*)pBuffer;
+
+	memset(pRndisHeader, 0, sizeof(struct RndisHeader));
+	pRndisHeader->MessageType = 0x01;
+	pRndisHeader->MessageLength = nMaxSize;
+	pRndisHeader->DataOffset = 0x24;
+	pRndisHeader->DataLength = nMaxSizeForDefaultPacket;
+	return true;
+}
+
+bool RNDISAggregationHelper::LoadEtherPacket(
+	enum ipa_ip_type eIP,
+	uint8_t *pBuffer,
+	size_t &nMaxSize)
+{
+	if (nMaxSize < sizeof(struct ethhdr))
+	{
+		LOG_MSG_ERROR("Buffer too small\n");
+		return false;
+	}
+
+	size_t nMaxSizeForDefaultPacket = nMaxSize - sizeof(struct ethhdr);
+
+	if (!LoadDefaultPacket(eIP, pBuffer + sizeof(struct ethhdr),
+		nMaxSizeForDefaultPacket))
+	{
+		LOG_MSG_ERROR("LoadDefaultPacket() failed\n");
+		return false;
+	}
+
+	nMaxSize = nMaxSizeForDefaultPacket + sizeof(struct ethhdr);
+	struct ethhdr *pEtherHeader = (struct ethhdr*)pBuffer;
+
+	memcpy(pEtherHeader, Eth2Helper::m_ETH2_IP4_HDR, sizeof(struct ethhdr));
+
+	print_buff(pBuffer, nMaxSize);
+	return true;
+
+
+}
+
+bool RNDISAggregationHelper::CompareIPvsRNDISPacket(
+	Byte *pIPPacket,
+	int ipPacketSize,
+	Byte *pRNDISPacket,
+	size_t rndisPacketSize)
+{
+	struct RndisHeader *pRndisHeader = (struct RndisHeader*)pRNDISPacket;
+
+	if (pRndisHeader->MessageType != 0x01)
+	{
+		LOG_MSG_ERROR("Wrong  MessageType 0x%8x\n",
+			pRndisHeader->MessageType);
+		return false;
+	}
+
+	if (pRndisHeader->MessageLength != rndisPacketSize)
+	{
+		LOG_MSG_ERROR(
+			"Packet sizes do not match 0x%8x expected 0x%8x\n",
+			pRndisHeader->MessageLength, rndisPacketSize);
+		return false;
+	}
+
+	// Create Ethernet packet from the IP packet and compare it to RNDIS payload
+	size_t EtherPacketSize = ipPacketSize + sizeof(struct ethhdr);
+	Byte* pEtherPacket = (Byte *) malloc(EtherPacketSize);
+	if (pEtherPacket == NULL) {
+		LOG_MSG_ERROR("Memory allocation failure.\n");
+		return false;
+	}
+
+	memcpy(pEtherPacket, Eth2Helper::m_ETH2_IP4_HDR, sizeof(struct ethhdr));
+	memcpy(pEtherPacket + sizeof(struct ethhdr), pIPPacket, ipPacketSize);
+
+	if (pRndisHeader->DataLength != EtherPacketSize)
+	{
+		LOG_MSG_ERROR(
+			"Packet sizes do not match 0x%8x expected 0x%8x\n",
+			pRndisHeader->DataLength, EtherPacketSize);
+		Free(pEtherPacket);
+		return false;
+	}
+
+	if(!ComparePackets(
+		(Byte*)&pRndisHeader->DataOffset + pRndisHeader->DataOffset,
+		EtherPacketSize, pEtherPacket, EtherPacketSize))
+	{
+		LOG_MSG_ERROR("Packets do not match\n");
+		Free(pEtherPacket);
+		return false;
+	}
+
+	Free(pEtherPacket);
+	return true;
+}
+
+bool RNDISAggregationHelper::CompareEthervsRNDISPacket(
+	Byte *pIPPacket,
+	size_t ipPacketSize,
+	Byte *pRNDISPacket,
+	size_t rndisPacketSize)
+{
+	struct RndisHeader *pRndisHeader = (struct RndisHeader*)pRNDISPacket;
+
+	if (pRndisHeader->MessageType != 0x01)
+	{
+		LOG_MSG_ERROR("Wrong  MessageType 0x%8x\n",
+			pRndisHeader->MessageType);
+		return false;
+	}
+
+	if (pRndisHeader->MessageLength != rndisPacketSize)
+	{
+		LOG_MSG_ERROR(
+			"Packet sizes do not match 0x%8x expected 0x%8x\n",
+			pRndisHeader->MessageLength, rndisPacketSize);
+		return false;
+	}
+
+	if (pRndisHeader->DataLength != ipPacketSize)
+	{
+		LOG_MSG_ERROR(
+			"Packet sizes do not match 0x%8x expected 0x%8x\n",
+			pRndisHeader->DataLength, ipPacketSize);
+		return false;
+	}
+
+	return ComparePackets(
+		(Byte*)&pRndisHeader->DataOffset + pRndisHeader->DataOffset,
+		ipPacketSize, pIPPacket, ipPacketSize);
+}
+
+bool RNDISAggregationHelper::ComparePackets(
+	Byte *pPacket,
+	int packetSize,
+	Byte *pExpectedPacket,
+	int expectedPacketSize)
+{
+	bool res = true;
+
+	if (packetSize != expectedPacketSize)
+	{
+		LOG_MSG_ERROR("Packet sizes do not match\n");
+		res = false;
+	}
+
+	for (int i = 0; i < packetSize; i++)
+	{
+		if (pPacket[i] != pExpectedPacket[i])
+		{
+			LOG_MSG_ERROR(
+				"Byte %d not match 0x%2x != 0x%2x\n",
+				i, pPacket[i], pExpectedPacket[i]);
+			res = false;
+		}
+	}
+
+	if (!res)
+	{
+		LOG_MSG_ERROR("Packet:\n");
+		print_buff(pPacket, packetSize);
+		LOG_MSG_ERROR("Expected Packet:\n");
+		print_buff(pExpectedPacket, expectedPacketSize);
+	}
+
+	return res;
+}
+
+
+#if !defined(MSM_IPA_TESTS) && !defined(USE_GLIB) && !defined(FEATURE_IPA_ANDROID)
+size_t strlcpy(char* dst, const char* src, size_t size)
+{
+	size_t i;
+
+	if (size == 0)
+		return strlen(src);
+
+	for (i = 0; i < (size - 1) && src[i] != '\0'; ++i)
+		dst[i] = src[i];
+
+	dst[i] = '\0';
+
+	return i + strlen(src + i);
+}
+#endif

+ 798 - 0
kernel-tests/TestsUtils.h

@@ -0,0 +1,798 @@
+/*
+ * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TESTS_UTILS__H__
+#define __TESTS_UTILS__H__
+
+#include <stdarg.h>
+#include <vector>
+#include <string>
+#include <linux/if_ether.h>
+#include <linux/msm_ipa.h>
+#include "TestBase.h"
+#include "Constants.h"
+#include "RoutingDriverWrapper.h"
+#include "InterfaceAbstraction.h"
+#include "ipa_test_module.h"
+#include "TestManager.h"
+#include "Logger.h"
+#include "Constants.h"
+extern "C" {
+#include "ipa_nat_utils.h"
+}
+
+using namespace std;
+#define TEST_APP_VERSION "2.00"
+
+#define Free(x) do { if (x) {free(x); x = NULL; } } while (0)
+
+#define MAX3(_X, _Y, _Z) max(max((_X), (_Y)), (_Z))
+
+#define ETH2_DST_ADDR_OFFSET (0)
+#define ETH2_SRC_ADDR_OFFSET (ETH_ALEN)
+#define ETH2_ETH_TYPE_OFFSET (ETH2_SRC_ADDR_OFFSET + ETH_ALEN)
+#define ETH2_ETH_TYPE_LEN (2)
+#define ETH2_PAYLOAD_OFFSET (ETH2_ETH_TYPE_OFFSET + ETH2_ETH_TYPE_LEN)
+
+#define ETH8021Q_HEADER_LEN (18)
+#define ETH8021Q_METADATA_OFFSET (12)
+#define ETH8021Q_8021Q_TAG_LEN (4)
+#define ETH8021Q_ETH_TYPE_OFFSET (ETH8021Q_METADATA_OFFSET + ETH8021Q_8021Q_TAG_LEN)
+
+#define WLAN_HDR_SIZE (4)
+#define RNDIS_HDR_SIZE (44)
+
+// 26 ROME WLAN Frame =
+// 4	ROME WLAN header +
+// 14	IEEE 802.3 +
+// 8	802.2 LLC/SNAP
+#define _802_3_HDR_SIZE (26)
+
+// [WLAN][ETH2] header
+#define WLAN_ETH2_HDR_SIZE (WLAN_HDR_SIZE + ETH_HLEN)
+
+// [RNDIS][ETH2] header
+#define RNDIS_ETH2_HDR_SIZE (RNDIS_HDR_SIZE + ETH_HLEN)
+#define IP4_PACKET_SIZE (70) // Arbitrary number
+
+// OFFSET = sizeof(struct rndis_pkt_hdr) - RNDIS_HDR_OFST(data_ofst)
+#define RNDIS_DATA_OFFSET (36)
+
+// [WLAN][802.3] header
+#define WLAN_802_3_HDR_SIZE (WLAN_HDR_SIZE + _802_3_HDR_SIZE)
+
+#define IPA_CLIENT_IS_PROD(x) \
+	(x < IPA_CLIENT_MAX && (x & 0x1) == 0)
+#define IPA_CLIENT_IS_CONS(x) \
+	(x < IPA_CLIENT_MAX && (x & 0x1) == 1)
+
+enum msgType {
+	ERROR = 0,
+	DEBUG,
+	INFO,
+	STACK
+};
+
+/**
+	@brief
+	Do not Use this function. Use MACROs instead.
+
+	@details
+	Do not Use this function.
+	Instead use the MACROs: LOG_MSG_ERROR, LOG_MSG_INFO & LOG_MSG_DEBUG
+	*/
+void __log_msg(enum msgType,
+		const char *filename,
+		int line, const char *function,
+		const char *format, ...);
+
+#define LOG_MSG_ERROR(...) \
+__log_msg(ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__)
+#define LOG_MSG_DEBUG(...) \
+__log_msg(DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__)
+#define LOG_MSG_INFO(...) \
+__log_msg(INFO, __FILE__, __LINE__, __func__, __VA_ARGS__)
+#define LOG_MSG_STACK(...) \
+__log_msg(STACK, __FILE__, __LINE__, __func__, __VA_ARGS__)
+
+/*#define LOG_MSG_ERROR(x...)
+__log_msg(ERROR, __FILE__, __LINE__, __func__, x)
+#define LOG_MSG_DEBUG(x...)
+__log_msg(DEBUG, __FILE__, __LINE__, __func__, x)
+#define LOG_MSG_INFO(x...)
+__log_msg(INFO, __FILE__, __LINE__, __func__, x)
+#define LOG_MSG_STACK(x...)
+__log_msg(STACK, __FILE__, __LINE__, __func__, x)*/
+
+/**
+	@brief
+	Function loads a default IPv4 / IPv6 Packet
+
+	@param [in] eIP - Type of Packet to load (IPA_IP_v4 / IPA_IP_v6)
+	@param [in] pBuffer - pointer to the destination buffer
+	@param [in,out] nMaxSize - The size of the buffer.
+	Upon function return,
+	the total number of bytes copied will be stored in this parameter.
+	@return boolean indicating whether the
+	operation completed successfully or not.
+
+	@details
+	Function loads a default IPv4 / IPv6 packet into pBuffer.
+	*/
+bool LoadDefaultPacket(
+	enum ipa_ip_type eIP,
+	uint8_t *pBuffer,
+	size_t &nMaxSize);
+
+bool LoadDefaultEth2Packet(
+	enum ipa_ip_type eIP,
+	uint8_t *pBuffer,
+	size_t &nMaxSize);
+
+bool LoadDefaultWLANEth2Packet(
+	enum ipa_ip_type eIP,
+	uint8_t *pBuffer,
+	size_t &nMaxSize);
+
+bool LoadDefaultWLAN802_32Packet(
+	enum ipa_ip_type eIP,
+	uint8_t *pBuffer,
+	size_t &nMaxSize);
+
+bool LoadNoPayloadPacket(
+	enum ipa_ip_type eIP,
+	uint8_t *pBuffer,
+	size_t &nMaxSize);
+
+bool LoadDefault802_1Q(
+	enum ipa_ip_type eIP,
+	uint8_t *pBuffer,
+	size_t &nMaxSize);
+
+/**
+	@brief
+	Function loads a default IPv4 / IPv6 Packet
+
+	@param [in] eIP - Type of Packet to load (IPA_IP_v4 / IPA_IP_v6)
+	@param [in] extHdrType - Type of IPV6 extension header(FRAGMENT / NONE)
+	@param [in] pBuffer - pointer to the destination buffer
+	@param [in,out] nMaxSize - The size of the buffer.
+	Upon function return,
+	the total number of bytes copied will be stored in this parameter.
+	@return boolean indicating whether the
+	operation completed successfully or not.
+
+	@details
+	Function loads a default IPv4 / IPv6 packet into pBuffer.
+	*/
+bool LoadDefaultPacket(
+		enum ipa_ip_type eIP,
+		enum ipv6_ext_hdr_type extHdrType,
+		uint8_t *pBuffer,
+		size_t &nMaxSize);
+/**
+	@brief
+	Function Sends a Packet, Receive a packet
+	and compares the received result with an expected buffer
+
+	@param [in] pSink - Destination to which a packet will be sent.
+	@param [in] pSendBuffer -
+	Pointer to a buffer containing the packet that will be sent.
+	@param [in] nSendBuffSize - The size of the data in the packet.
+	@param [in] pSource - Source from which a packet will be received.
+	@param [in] pExpectedBuffer - Pointer a
+	buffer containing the expected packet (from the receiver)
+	@param [in] nExpectedBuffSize - The size of
+	valid data within pExpectedBuffer.
+	@return Boolean indicating whether the operation
+	completed successfully and the buffers matching or not.
+
+	@details
+	Function sends a packet to pSink, and receives a packet from pSource.
+	The packet received from pSource
+	is compared to the expected data from pExpectedBuffer.
+	If ExpectData is identical to the
+	received data, the function returns TRUE.
+	*/
+bool SendReceiveAndCompare(
+		InterfaceAbstraction * pSink,
+		uint8_t *pSendBuffer,
+		size_t nSendBuffSize,
+		InterfaceAbstraction * pSource,
+		uint8_t *pExpectedBuffer,
+		size_t nExpectedBuffSize);
+
+/**
+	@brief
+	This function creates a bypass rule within a table in the Routing block
+
+	@param [in] pRouting - pointer to the Routing Class
+	@param [in] eIP - Type of Packet to load (IPA_IP_v4 / IPA_IP_v6)
+	@param [in] pTableName - pointer to the Table's Name.
+	@param [in] eRuleDestination - destination of the bypass rule.
+	@param [in] uHeaderHandle -
+	handle to the Header that should be Added (0 should be used as default).
+	@param [out] pTableHdl -
+	pointer to the table Handle (Can be Null)
+	@return boolean indicating whether
+	the operation completed successfully or not.
+
+	@details
+	This function creates bypass rule within a table in the Routing block.
+	*/
+bool CreateBypassRoutingTable(
+		RoutingDriverWrapper * pRouting,
+		enum ipa_ip_type eIP,
+		const char *pTableName,
+		enum ipa_client_type eRuleDestination,
+		uint32_t uHeaderHandle,
+		uint32_t *pTableHdl);
+
+/**
+	@brief
+	This function creates a bypass rule within a table in the Routing block
+
+	@param [in] pRouting - pointer to the Routing Class
+	@param [in] eIP - Type of Packet to load (IPA_IP_v4 / IPA_IP_v6)
+	@param [in] pTableName - pointer to the Table's Name.
+	@param [in] eRuleDestination - destination of the bypass rule.
+	@param [in] uHeaderHandle -
+	handle to the Header that should be Added (0 should be used as default).
+	@param [out] pTableHdl -
+	pointer to the table Handle (Can be Null)
+	@return boolean indicating whether
+	the operation completed successfully or not.
+
+	@details
+	This function creates bypass rule within a table in the Routing block.
+	*/
+bool CreateBypassRoutingTable_v2(
+		RoutingDriverWrapper * pRouting,
+		enum ipa_ip_type eIP,
+		const char *pTableName,
+		enum ipa_client_type eRuleDestination,
+		uint32_t uHeaderHandle,
+		uint32_t *pTableHdl,
+		uint8_t uClsAggrIrqMod);
+
+/**
+	@brief
+		Configures the sytem to one of the pre-determined
+		configurations.
+
+		@param [in] testConfiguration - Configuration number
+		@param [in] params - additional parameters
+	@return void
+
+	@details
+		Writes the configuration index to /dev/ipa_test. In case
+		the system has already been configured, returns.
+*/
+void ConfigureScenario(int testConfiguration);
+void ConfigureScenario(int testConfiguration, const char *params);
+int GenericConfigureScenario(struct ipa_test_config_header *header);
+int GenericConfigureScenarioDestory(void);
+int ConfigureSystem(int testConfiguration, int fd);
+int ConfigureSystem(int testConfiguration, int fd, const char *params);
+
+void prepare_channel_struct(struct ipa_channel_config *channel,
+		int index,
+		enum ipa_client_type client,
+		void *cfg,
+		size_t config_size,
+		bool en_status = 0);
+
+void prepare_header_struct(struct ipa_test_config_header *header,
+		struct ipa_channel_config **from,
+		struct ipa_channel_config **to);
+
+/**
+	@brief
+		Compares two data buffers.
+
+		@param [in] goldenBuffer - Pointer to the first data
+			buffer
+		@param [in] goldenSize - First data buffer size
+		@param [in] receivedBuffer - Pointer to the second data
+			buffer
+		@param [in] receivedSize - Second data buffer size
+		@return True - the buffers are identical. False
+			otherwise.
+
+		@details
+	In case the sizes are differnt, false is returned.
+*/
+bool CompareResultVsGolden(
+		unsigned char *goldenBuffer,
+		unsigned int goldenSize,
+		unsigned char *receivedBuffer,
+		unsigned int receivedSize);
+
+/**
+	@brief
+		Compares two data buffers considering the returned status.
+
+		@param [in] goldenBuffer - Pointer to the first data
+			buffer
+		@param [in] goldenSize - First data buffer size
+		@param [in] receivedBuffer - Pointer to the second data
+			buffer
+		@param [in] receivedSize - Second data buffer size
+		@return True - the buffers are identical. False
+			otherwise.
+
+		@details
+	In case the sizes are differnt, false is returned.
+*/
+bool CompareResultVsGolden_w_Status(
+	Byte *goldenBuffer,
+	unsigned int goldenSize,
+	Byte *receivedBuffer,
+	unsigned int receivedSize);
+
+
+/**
+	@brief
+		Loads a file to memory
+
+		@param [in] fileFullPath
+		@param [inout] sizeLoaded - returns the number of bytes
+			which were read from the file
+	@return Address of the loaded data buffer
+
+		@details
+		Allocates memory by itself, user should free the memory
+
+*/
+unsigned char *LoadFileToMemory(
+		const string & fileFullPath,
+		unsigned int *sizeLoaded);
+
+/**
+		@brief
+		Checks whether a file exists on disk
+
+		@param [in] filename
+	@return True if the file exists, false otherwise.
+
+		@details
+*/
+bool file_exists(const char *filename);
+
+/**
+		@brief
+		Prints a data buffer.
+		@param [in] data - Pointer to the data
+		@param [in] size - How many bytes to print
+	@return void
+
+		@details
+*/
+void print_buff(void *data, size_t size);
+
+void add_buff(uint8_t *data, size_t size, uint8_t val);
+
+/**
+		@brief
+		Performes ep control of a specific endpoint.
+		@param [in] ep_ctrl - Pointer to ipa_test_ep_ctrl struct with
+					the data of the requested operation
+	@return bool
+
+		@details
+		Suspend\Unsuspends\Delays\resumes an endpoint.
+*/
+bool configure_ep_ctrl(struct ipa_test_ep_ctrl *ep_ctrl);
+
+/**
+		@brief
+		Performes holb config of a specific pipe.
+ *  	@param [in] test_holb_config - Pointer to
+ *  				ipa_test_holb_config struct with the data of
+ *  				the requested operation
+	@return bool
+
+		@details
+		Configures HOLB parameters on a pipe.
+*/
+bool configure_holb(struct ipa_test_holb_config *test_holb_config);
+
+/**
+		@brief
+		Register an alternative suspend handler
+		@param [in] deferred_flag - should the handler execute in defer mode
+		@param [in] reg - register or unregister the suspend handler
+		@param [in] DevNum - the index of the ep that the handler is registered to
+	@return bool
+
+		@details
+		Register the test framework suspend handler for a given endpoint
+*/
+bool RegSuspendHandler(bool deferred_flag, bool reg, int DevNum);
+
+class Eth2Helper {
+public:
+	static const Byte m_ETH2_IP4_HDR[ETH_HLEN];
+
+	static bool LoadEth2IP4Header(
+		uint8_t *pBuffer,
+		size_t bufferSize,
+		size_t *pLen);
+
+	static bool LoadEth2IP6Header(
+		uint8_t *pBuffer,
+		size_t bufferSize,
+		size_t *pLen);
+
+	static bool LoadEth2IP4Packet(
+		uint8_t *pBuffer,
+		size_t bufferSize,
+		size_t *pLen);
+
+	static bool LoadEth2IP6Packet(
+		uint8_t *pBuffer,
+		size_t bufferSize,
+		size_t *pLen);
+};
+
+class WlanHelper {
+public:
+	static const Byte m_WLAN_HDR[WLAN_HDR_SIZE];
+
+	static bool LoadWlanHeader(
+		uint8_t *pBuffer,
+		size_t bufferSize,
+		size_t *pLen);
+
+	static bool LoadWlanEth2IP4Header(
+		uint8_t *pBuffer,
+		size_t bufferSize,
+		size_t *pLen);
+
+	static bool LoadWlanEth2IP6Header(
+		uint8_t *pBuffer,
+		size_t bufferSize,
+		size_t *pLen);
+
+	static bool LoadWlanEth2IP4Packet(
+		uint8_t *pBuffer,
+		size_t bufferSize,
+		size_t *pLen);
+
+	static bool LoadWlanEth2IP4PacketByLength(
+		uint8_t *pBuffer,
+		size_t bufferSize,
+		size_t len,
+		uint8_t padValue);
+
+	static bool LoadWlanEth2IP6Packet(
+		uint8_t *pBuffer,
+		size_t bufferSize,
+		size_t *pLen);
+};
+
+#pragma pack(push)  /* push current alignment to stack */
+#pragma pack(1)     /* set alignment to 1 byte boundary */
+struct RndisHeader {
+	uint32_t MessageType;
+	uint32_t MessageLength;
+	uint32_t DataOffset;
+	uint32_t DataLength;
+	uint32_t OOBDataOffset;
+	uint32_t OOBDataLength;
+	uint32_t OOBNumber;
+	uint32_t PacketInfoOffset;
+	uint32_t PacketInfoLength;
+	uint64_t Reserved;
+};
+
+struct RndisEtherHeader {
+	struct RndisHeader rndisHeader;
+	struct ethhdr etherHeader;
+};
+#pragma pack(pop)   /* restore original alignment from stack */
+
+class RNDISAggregationHelper {
+public:
+	static const size_t RNDIS_AGGREGATION_BYTE_LIMIT = 1024;
+
+	static bool LoadRNDISHeader(
+		uint8_t *pBuffer,
+		size_t bufferSize,
+		uint32_t messageLength,
+		size_t *pLen);
+
+	static bool LoadRNDISEth2IP4Header(
+		uint8_t *pBuffer,
+		size_t bufferSize,
+		uint32_t messageLength,
+		size_t *pLen);
+
+	static bool LoadRNDISPacket(
+		enum ipa_ip_type eIP,
+		uint8_t *pBuffer,
+		size_t &nMaxSize);
+
+	static bool LoadEtherPacket(
+		enum ipa_ip_type eIP,
+		uint8_t *pBuffer,
+		size_t &nMaxSize);
+
+	static bool ComparePackets(
+		Byte *pPacket1,
+		int pPacket1Size,
+		Byte *pPacket2,
+		int pPacket2Size);
+
+	static bool CompareEthervsRNDISPacket(
+		Byte *pIPPacket,
+		size_t ipPacketSize,
+		Byte *pRNDISPacket,
+		size_t rndisPacketSize);
+
+	static bool CompareIPvsRNDISPacket(
+		Byte *pIPPacket,
+		int ipPacketSize,
+		Byte *pRNDISPacket,
+		size_t rndisPacketSize);
+};
+
+enum ipa_nat_en_type {
+	IPA_BYPASS_NAT,
+	IPA_SRC_NAT,
+	IPA_DST_NAT,
+};
+
+enum ipa_ipv6ct_en_type {
+	IPA_BYPASS_IPV6CT,
+	IPA_ENABLE_IPV6CT,
+};
+
+enum ipa_mode_type {
+	IPA_BASIC,
+	IPA_ENABLE_FRAMING_HDLC,
+	IPA_ENABLE_DEFRAMING_HDLC,
+	IPA_DMA,
+};
+
+enum ipa_aggr_en_type {
+	IPA_BYPASS_AGGR,
+	IPA_ENABLE_AGGR,
+	IPA_ENABLE_DEAGGR,
+};
+
+enum ipa_aggr_type {
+	IPA_MBIM_16 = 0,
+	IPA_HDLC    = 1,
+	IPA_TLP     = 2,
+	IPA_RNDIS   = 3,
+	IPA_GENERIC = 4,
+	IPA_QCMAP   = 6,
+};
+
+enum ipa_aggr_mode {
+	IPA_MBIM_AGGR,
+	IPA_QCNCM_AGGR,
+};
+
+enum hdr_total_len_or_pad_type {
+	IPA_HDR_PAD = 0,
+	IPA_HDR_TOTAL_LEN = 1,
+};
+
+struct ipa_ep_cfg_nat {
+	enum ipa_nat_en_type nat_en;
+};
+
+struct ipa_ep_cfg_conn_track {
+	enum ipa_ipv6ct_en_type conn_track_en;
+};
+
+struct ipa_ep_cfg_hdr {
+	uint32_t hdr_len;
+	uint32_t hdr_ofst_metadata_valid;
+	uint32_t hdr_ofst_metadata;
+	uint32_t hdr_additional_const_len;
+	uint32_t hdr_ofst_pkt_size_valid;
+	uint32_t hdr_ofst_pkt_size;
+	uint32_t hdr_a5_mux;
+	uint32_t hdr_remove_additional;
+	uint32_t hdr_metadata_reg_valid;
+};
+
+struct ipa_ep_cfg_hdr_ext {
+	uint32_t hdr_pad_to_alignment;
+	uint32_t hdr_total_len_or_pad_offset;
+	bool hdr_payload_len_inc_padding;
+	enum hdr_total_len_or_pad_type hdr_total_len_or_pad;
+	bool hdr_total_len_or_pad_valid;
+	bool hdr_little_endian;
+	struct ipa_ep_cfg_hdr *hdr;
+	bool hdr_bytes_to_remove_valid;
+	uint32_t hdr_bytes_to_remove;
+};
+
+struct ipa_ep_cfg_mode {
+	enum ipa_mode_type mode;
+	enum ipa_client_type dst;
+};
+
+struct ipa_ep_cfg_aggr {
+	enum ipa_aggr_en_type aggr_en;
+	enum ipa_aggr_type aggr;
+	uint32_t aggr_byte_limit;
+	uint32_t aggr_time_limit;
+	uint32_t aggr_pkt_limit;
+	uint32_t aggr_hard_byte_limit_en;
+	bool aggr_sw_eof_active;
+	uint8_t pulse_generator;
+	uint8_t scaled_time;
+};
+
+struct ipa_ep_cfg_route {
+	uint32_t rt_tbl_hdl;
+};
+
+struct ipa_ep_cfg_deaggr {
+	uint32_t deaggr_hdr_len;
+	bool syspipe_err_detection;
+	bool packet_offset_valid;
+	uint32_t packet_offset_location;
+	bool ignore_min_pkt_err;
+	uint32_t max_packet_len;
+};
+
+enum ipa_cs_offload {
+	IPA_DISABLE_CS_OFFLOAD,
+	IPA_ENABLE_CS_OFFLOAD_UL,
+	IPA_ENABLE_CS_OFFLOAD_DL,
+	IPA_CS_RSVD
+};
+
+struct ipa_ep_cfg_cfg {
+	bool frag_offload_en;
+	enum ipa_cs_offload cs_offload_en;
+	uint8_t cs_metadata_hdr_offset;
+	uint8_t gen_qmb_master_sel;
+	uint8_t tx_instance;
+};
+
+struct ipa_ep_cfg_metadata_mask {
+	uint32_t metadata_mask;
+};
+
+struct ipa_ep_cfg_metadata {
+	uint32_t qmap_id;
+};
+
+struct ipa_ep_cfg_seq {
+	bool set_dynamic;
+	int seq_type;
+};
+
+struct ipa_ep_cfg_holb {
+	uint32_t tmr_val;
+	uint32_t base_val;
+	uint32_t scale;
+	uint16_t en;
+	uint8_t pulse_generator;
+	uint8_t scaled_time;
+};
+
+/*
+ * This struct is a mirroring of the ipa struct
+ * the test module expect to get from user-space the
+ * exact same struct as IPA driver defined.
+ * In case of any change to IPA driver struct
+ * this struct should be updated as well!
+ */
+struct test_ipa_ep_cfg {
+	struct ipa_ep_cfg_nat nat;
+	struct ipa_ep_cfg_conn_track conn_track;
+	struct ipa_ep_cfg_hdr hdr;
+	struct ipa_ep_cfg_hdr_ext hdr_ext;
+	struct ipa_ep_cfg_mode mode;
+	struct ipa_ep_cfg_aggr aggr;
+	struct ipa_ep_cfg_deaggr deaggr;
+	struct ipa_ep_cfg_route route;
+	struct ipa_ep_cfg_cfg cfg;
+	struct ipa_ep_cfg_metadata_mask metadata_mask;
+	struct ipa_ep_cfg_metadata meta;
+	struct ipa_ep_cfg_seq seq;
+};
+
+/*! @brief Struct for the IPAv3.0 UL packet status header */
+struct ipa3_hw_pkt_status {
+	uint64_t status_opcode:8;
+	uint64_t exception:8;
+	uint64_t status_mask:16;
+	uint64_t pkt_len:16;
+	uint64_t endp_src_idx:5;
+	uint64_t reserved_1:3;
+	uint64_t endp_dest_idx:5;
+	uint64_t reserved_2:3;
+	uint64_t metadata:32;
+	uint64_t filt_local:1;
+	uint64_t filt_hash:1;
+	uint64_t filt_global:1;
+	uint64_t ret_hdr:1;
+	uint64_t filt_rule_id:10;
+	uint64_t route_local:1;
+	uint64_t route_hash:1;
+	uint64_t ucp:1;
+	uint64_t route_tbl_idx:5;
+	uint64_t route_rule_id:10;
+	uint64_t nat_hit:1;
+	uint64_t nat_tbl_idx:13;
+	uint64_t nat_type:2;
+	uint64_t tag:48;
+	uint64_t seq_num:8;
+	uint64_t time_day_ctr:24;
+	uint64_t hdr_local:1;
+	uint64_t hdr_offset:10;
+	uint64_t frag_hit:1;
+	uint64_t frag_rule:4;
+	uint64_t reserved_4:16;
+};
+
+struct ipa3_hw_pkt_status_hw_v5_0 {
+	uint64_t status_opcode : 8;
+	uint64_t exception : 8;
+	uint64_t status_mask : 16;
+	uint64_t pkt_len : 16;
+	uint64_t endp_src_idx : 8;
+	uint64_t reserved_1 : 3;
+	uint64_t route_local : 1;
+	uint64_t route_hash : 1;
+	uint64_t reserved_2 : 3;
+	uint64_t metadata : 32;
+	uint64_t filt_local : 1;
+	uint64_t filt_hash : 1;
+	uint64_t filt_global : 1;
+	uint64_t ret_hdr : 1;
+	uint64_t filt_rule_id : 10;
+	uint64_t route_tbl_idx : 8;
+	uint64_t route_rule_id : 10;
+	uint64_t nat_hit : 1;
+	uint64_t nat_tbl_idx : 13;
+	uint64_t nat_type : 2;
+	uint64_t tag : 48;
+	uint64_t seq_num : 8;
+	uint64_t time_day_ctr : 24;
+	uint64_t hdr_local : 1;
+	uint64_t hdr_offset : 10;
+	uint64_t frag_hit : 1;
+	uint64_t frag_rule : 4;
+	uint64_t endp_dest_idx : 8;
+	uint64_t reserved_4 : 7;
+	uint64_t ucp : 1;
+};
+
+
+#endif

+ 12 - 0
kernel-tests/autogen.sh

@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# autogen.sh -- Autotools bootstrapping
+#
+
+AUTO_TOOLS_VER=$(automake --version | grep ^automake | sed 's/^.* //g' | cut -d'.' -f1-2)
+
+aclocal-${AUTO_TOOLS_VER} &&\
+autoheader &&\
+autoconf &&\
+automake-${AUTO_TOOLS_VER} --add-missing --copy
+

+ 129 - 0
kernel-tests/build_kernel_tests.py

@@ -0,0 +1,129 @@
+#! /usr/bin/env python
+
+# Copyright (c) 2021, The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of The Linux Foundation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import os.path
+import subprocess
+import sys
+import shutil
+
+install_dir = '/ipa-kernel-tests'  # unlikely to ever change, so 'file constant'
+
+
+def get_args():
+    class Args:
+        pass
+
+    args = Args()
+
+    try:
+        args.cc_path = os.path.dirname(os.environ['CROSS_COMPILE'])
+    except:
+        args.cc_path = None
+
+    try:
+        args.arch = os.environ['ARCH']
+    except:
+        raise Exception("ARCH must be set")
+
+    try:
+        args.kdir = os.environ['KDIR']
+    except:
+        raise Exception("KDIR must be set")
+
+    try:
+        args.dest = os.environ['DESTDIR']
+    except:
+        raise Exception("DESTDIR must be set")
+
+    return args
+
+
+def do(cmd, wdir=None):
+    cwd = None
+    if wdir:
+        cwd = os.getcwd()
+        os.chdir(wdir)
+    subprocess.check_call(cmd)
+    if cwd:
+        os.chdir(cwd)
+
+
+def build(args):
+
+    if args.cc_path:
+        os.environ['PATH'] = args.cc_path + ':' + os.environ['PATH']
+
+    args.uapi = args.kdir + '/usr/include'
+    args.src = args.kdir + '/techpack/dataipa/kernel-tests'
+    args.inc = args.kdir + '/techpack/dataipa/drivers/platform/msm/ipa/ipa_test_module'
+
+    full_uapi = os.path.abspath(args.uapi)
+    os.environ['CPPFLAGS'] = ('-I' + full_uapi)
+    full_inc = os.path.abspath(args.inc)
+    os.environ['CPPFLAGS'] += (' -I' + full_inc)
+
+    configure(args, args.src)
+
+    do(['make'], args.src)
+    do(['make', 'DESTDIR=' + args.dest, 'install'], args.src)
+
+
+def configure(args, wdir):
+
+    if os.path.isfile(os.path.join(wdir, 'config.h')):
+        return
+
+    do(['libtoolize'], wdir)
+    do(['./autogen.sh'], wdir)
+
+    full_idir = os.path.abspath(os.path.join(wdir, install_dir))
+    host_str = 'arm-linux-gnueabihf'
+    config_extra = ''
+    if args.arch == 'arm64':
+        host_str = 'aarch64-linux-gnu'
+        config_extra = '--disable-swp'
+    do(['./configure',
+        '--host=' + host_str,
+        '--prefix=' + full_idir,
+        config_extra], wdir)
+
+
+def main():
+    rc = 0
+    try:
+        args = get_args()
+        build(args)
+    except Exception as e:
+        rc = 1
+        print(e)
+        sys.exit(rc)
+
+if __name__ == '__main__':
+    main()

+ 56 - 0
kernel-tests/configure.ac

@@ -0,0 +1,56 @@
+AC_PREREQ(2.64)
+
+AC_INIT([ipa-kernel-tests],[1.0.0])
+AM_INIT_AUTOMAKE([-Wall -Werror gnu foreign])
+
+AM_MAINTAINER_MODE
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_CC
+AM_PROG_CC_C_O
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+AC_PROG_LIBTOOL
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AC_PROG_CXX
+
+
+AS_CASE([$host],
+        [aarch64*], [ARM64=yes],
+        [ARM64=no]
+)
+
+AM_CONDITIONAL(ARM64, [test "x$ARM64" = "xyes"])
+
+AC_ARG_WITH([glib],
+       AC_HELP_STRING([--with-glib],
+          [enable glib, building HLOS systems which use glib]))
+
+AC_ARG_WITH(ipanat-headers,
+      AS_HELP_STRING([--with-ipanat-headers=DIR],
+         [Specify the location of the ipanat headers]),
+      [CPPFLAGS="$CPPFLAGS -idirafter $withval"])
+
+if (test "x${with_glib}" = "xyes"); then
+         AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
+         PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+                                 AC_MSG_ERROR(GThread >= 2.16 is required))
+         PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+                                 AC_MSG_ERROR(GLib >= 2.16 is required))
+         GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+         GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+
+         AC_SUBST(GLIB_CFLAGS)
+         AC_SUBST(GLIB_LIBS)
+fi
+
+AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
+
+AC_CONFIG_FILES([
+	Makefile
+	])
+AC_OUTPUT

+ 80 - 0
kernel-tests/create_symlinks.sh

@@ -0,0 +1,80 @@
+# Copyright (c) 2021, The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of The Linux Foundation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This script creates symlinks for tests that are compiled as Soong modules, so
+# that they may be accessed from their old location in /data/kernel-tests
+
+#!/bin/sh
+
+NTEST_PATH="/data/nativetest"
+KTEST_PATH="/data/kernel-tests"
+
+# Any test that is compiled as a cc_test module (which applies to any Soong
+# module in kernel-tests-internal) is given a directory, in to which the
+# compiled test and its supporting files are placed.  This function iterates
+# over the test directories in $1 and creates symlinks to all the files
+# contained within a given test directory. $2 and later arguemnts can be used to
+# specify directores to skip.
+create_links()
+{
+    BASE_PATH="$1"
+    shift
+    SKIP_FILES=$@ # These can also be directories
+
+    for TEST_DIR in `ls "$BASE_PATH"`; do
+        # Filter out any file / directory in SKIP_FILES.
+        SHOULD_SKIP=""
+        for i in $SKIP_FILES; do
+            if [ "$TEST_DIR" = "$i" ]; then
+                SHOULD_SKIP="TRUE"
+                break
+            fi
+        done
+        if [ ! "$SHOULD_SKIP" = "" ]; then
+            continue
+        fi
+
+
+        # Filter out any files that aren't directories (since every test we
+        # compile is given a directory)
+        if [ ! -d "$BASE_PATH/$TEST_DIR" ]; then
+            continue
+        fi
+
+        # Now, create the symlinks for each test file inside of TEST_DIR
+        for TEST_FILE in `ls "$BASE_PATH/$TEST_DIR"`; do
+            ln -fs "$BASE_PATH/$TEST_DIR/$TEST_FILE" "$KTEST_PATH/$TEST_FILE"
+        done
+    done
+}
+
+# Create /data/kernel-tests, if it doesn't exist already
+mkdir -p "$KTEST_PATH"
+
+# Create the symlinks
+create_links "$NTEST_PATH" "vendor"
+create_links "$NTEST_PATH/vendor"

+ 39 - 0
kernel-tests/hton.h

@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HTON_H_
+#define HTON_H_
+
+#include <stdint.h>
+#include "linux/msm_ipa.h"
+
+#include <netinet/in.h>
+
+#endif
+

+ 388 - 0
kernel-tests/main.cpp

@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2017-2018,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <getopt.h>
+
+#include "Logger.h"
+#include "TestManager.h"
+#include "TestsUtils.h"
+#include <stdio.h>
+#include <iostream>
+#include <set>
+///////////////////////////////////////////////////////////
+
+Logger g_Logger(LOG_ERROR);
+#define CHOOSER_MODE   "--chooser"
+#define SHOW_TEST_FLAG "--show_tests"
+#define SHOW_SUIT_FLAG "--show_suites"
+#define RUN_TEST_FLAG  "--test"
+#define RUN_SUIT_FLAG  "--suite"
+string sFormat = "ip_accelerator <control_flag> <suit/name>, ..., <suit/name>\n"
+							"contorl_flag = "   RUN_TEST_FLAG  " or "  RUN_SUIT_FLAG "\n"
+							"ip_accelerator " SHOW_TEST_FLAG  "\n"
+							"ip_accelerator " SHOW_SUIT_FLAG  "\n"
+							"or ip_accelerator --chooser "
+							"for menu chooser interface\n";
+#define MAX_SUITES 15
+
+#undef strcasesame
+#define strcasesame(x, y) \
+	(! strcasecmp((x), (y)))
+
+#undef legal_nat_mem_type
+#define legal_nat_mem_type(mt) \
+	( strcasesame(mt, "DDR") || \
+	  strcasesame(mt, "SRAM") || \
+	  strcasesame(mt, "HYBRID") )
+
+TestManager *testmanager = NULL;
+
+enum ipa_test_type{
+	TEST = 1,
+	SUITE,
+	EXIT,
+	MAX_TYPE
+};
+
+const char *ipa_hw_type_name[] = {
+	"None",
+	"1.0",
+	"1.1",
+	"2.0",
+	"2.1",
+	"2.5/2.6",
+	"2.6L",
+	"Unused",
+	"Unused",
+	"Unused",
+	"3.0",
+	"3.1",
+	"3.5",
+	"3.5.1",
+	"4.0",
+	"4.1",
+	"4.2",
+	"4.5",
+	"4.9",
+	"5.0",
+	"MAX"
+};
+
+void BuildRegressionTestSuite()
+{
+	TestBase *test;
+
+	for (unsigned int i = 0; i < testmanager->m_testList.size(); i++) {
+		test = testmanager->m_testList[i];
+		if (test->m_runInRegression) {
+			test->m_testSuiteName.push_back("Regression");
+		}
+	}
+}
+
+
+///////////////////////////////////////////////////////////
+void showTests()
+{
+	TestBase *test = testmanager->m_testList[0];
+
+	for (unsigned  i = 0; i < testmanager->m_testList.size(); i++) {
+		test = testmanager->m_testList[i];
+		string name = test->m_name, index = test->m_testSuiteName[0];
+
+		printf("%d) %s (part of %s suite" ,i+1, name.c_str(), index.c_str());
+		for (unsigned j = 0; j < test->m_testSuiteName.size(); ++j) {
+			if ( test->m_testSuiteName[j] == index)
+				continue;
+			printf(", %s suite",
+				 test->m_testSuiteName[j].c_str());
+			index = test->m_testSuiteName[j];
+		}
+		printf("), (%s <= HW Version <= %s)\n",
+		       ipa_hw_type_name[test->m_minIPAHwType],
+		       ipa_hw_type_name[test->m_maxIPAHwType]);
+	}
+
+	// Example:
+	// 15) DmaModeMBIMggregationLoopTest (part of DmaMbim16Agg suite), (1.0 <= HW Version <= 2.1)
+}
+
+void showSuits()
+{
+	TestBase *test;
+	std::set<string> suiteSet;
+	int suiteIndex = 1;
+
+	test = testmanager->m_testList[0];
+
+	for (unsigned  i = 0; i < testmanager->m_testList.size(); i++) {
+		test = testmanager->m_testList[i];
+		for (unsigned j = 0; j < test->m_testSuiteName.size() ; j++)
+			suiteSet.insert(test->m_testSuiteName[j]);
+	}
+
+	for (std::set<string>::iterator i = suiteSet.begin();
+			i != suiteSet.end(); suiteIndex++) {
+		printf("%d) %s\n", suiteIndex, (*i).c_str());
+		++i;
+	}
+}
+
+void preparTests(int argc, char* argv[],
+		vector<string>& list)
+{
+	for (int i = 2; i < argc; i++)
+		list.push_back(argv[i]);
+}
+
+const char* getSuite(int suite_num) {
+	int count = 0, suiteIndex = 1;
+	string result = "error";
+	TestBase *test = testmanager->m_testList[0];
+	set<string> suiteSet;
+
+	if (testmanager->m_testList.size() < 1)
+		return NULL;
+
+	if (count == suite_num)
+		return testmanager->m_testList[0]->m_testSuiteName[0].c_str();
+
+	for (unsigned  i = 0; i < testmanager->m_testList.size(); i++) {
+		test = testmanager->m_testList[i];
+		for (unsigned j = 0; j < test->m_testSuiteName.size() ; j++)
+			suiteSet.insert(test->m_testSuiteName[j]);
+	}
+
+	for (std::set<string>::iterator i = suiteSet.begin();
+			i != suiteSet.end(); suiteIndex++) {
+		printf("%d) %s\n", suiteIndex, (*i).c_str());
+		if (suiteIndex == suite_num)
+			return (*i).c_str();
+		++i;
+	}
+	return NULL;
+}
+
+int chooserMode() {
+	vector<string> testSuiteList;
+	vector<string> testNameList;
+	unsigned int test_num;
+	int suite_num;
+	int type;
+	TestBase *test;
+	const char* res;
+	int result = 0;
+	char input_str[4];
+
+	printf("Welcome to the ip_accelerator\nChoose an option:\n");
+	printf("1) Run tests\n2) Run suites\n3) Exit\nChoose an option: ");
+	res = fgets(input_str, sizeof(input_str), stdin);
+	type = atoi(input_str);
+	switch((enum ipa_test_type)type) {
+	case TEST:
+		BuildRegressionTestSuite();
+		showTests();
+		printf("Choose which test you wish to run: \n");
+		fflush(stdin);
+		res = fgets(input_str, sizeof(input_str), stdin);
+		test_num = atoi(input_str);
+		if ( test_num > testmanager->m_testList.size()) {
+			printf("Invalid test number. Try again\n");
+			result = -1;
+			break;
+		}
+		test = testmanager->m_testList[test_num-1];
+		printf("Running Test %s\n",
+				test->m_name.
+				c_str());
+		testNameList.push_back(test->m_name.c_str());
+		BuildRegressionTestSuite();
+		testmanager->Run(testSuiteList, testNameList);
+		testNameList.clear();
+		break;
+	case SUITE:
+		BuildRegressionTestSuite();
+		showSuits();
+		printf("Choose which suite you wish to run: \n");
+		fflush(stdin);
+		res = fgets(input_str, sizeof(input_str), stdin);
+		suite_num = atoi(input_str);
+		if (suite_num < 0 || suite_num > MAX_SUITES) {
+			printf("Invalid test number. Try again\n");
+			result = -1;
+			break;
+		}
+		res = getSuite(suite_num);
+		if	(!res) {
+			printf("Error in getSuite. Exiting\n");
+			result = -1;
+			break;
+		}
+		testSuiteList.push_back(res);
+		testmanager->Run(testSuiteList, testNameList);
+		testSuiteList.clear();
+		break;
+	default:
+		printf("Exiting\n");
+		break;
+	}
+	return result;
+}
+
+int scriptMode(int argc, char* argv[]) {
+	vector<string> testSuiteList;
+	vector<string> testNameList;
+	string sControlFlag;
+
+	if (argc < 2) {
+		printf("please use correct format:\n%s", sFormat.c_str());
+		return -1;
+	}
+
+	sControlFlag = argv[1];
+
+	if (sControlFlag.find("--") == string::npos) {
+		printf("please use correct format:\n%s", sFormat.c_str());
+		return -1;
+	}
+
+	BuildRegressionTestSuite();
+
+	if (sControlFlag.compare(SHOW_TEST_FLAG) == 0) {
+		showTests();
+		return 0;
+	} else if (sControlFlag.compare(SHOW_SUIT_FLAG) == 0) {
+		showSuits();
+		return 0;
+	}
+
+	if (sControlFlag.compare(RUN_TEST_FLAG) == 0) {
+		preparTests(argc, argv, testNameList);
+	} else if (sControlFlag.compare(RUN_SUIT_FLAG) == 0) {
+		preparTests(argc, argv, testSuiteList);
+	} else {
+		printf("please use correct format:\n%s", sFormat.c_str());
+		return -1;
+	}
+
+	testmanager->Run(testSuiteList, testNameList);
+	return 0;
+}
+
+int main(int argc, char* argv[])
+{
+	string nat_mem_type = DFLT_NAT_MEM_TYPE;
+
+	int c, result = 0, what = 0;
+
+	int opt_idx = 0;
+
+	struct option opts[] = {
+		/* These options set a flag. */
+		{"chooser",     no_argument,       &what, 1},
+		{"show_tests",  no_argument,       &what, 2},
+		{"show_suites", no_argument,       &what, 3},
+		{"test",        no_argument,       &what, 4},
+		{"suite",       no_argument,       &what, 5},
+		{"mem",         required_argument, 0,    'm'},
+		{0, 0, 0, 0}
+	};
+
+	if (argc <= 1) {
+		printf("please use correct format:\n%s", sFormat.c_str());
+		return -1;
+	}
+
+	while ( (c = getopt_long(argc, argv, "", opts, &opt_idx)) != -1 )
+	{
+		switch ( c )
+		{
+		case 0:
+			break;
+		case 'm':
+			if ( legal_nat_mem_type(optarg) )
+			{
+				nat_mem_type = optarg;
+			}
+			else
+			{
+				fprintf(stderr, "Illegal: --mem %s\n", optarg);
+				exit(1);
+			}
+			break;
+		default:
+			fprintf(stderr, "Illegal command line argument passed\n");
+			printf("please use correct format:\n%s", sFormat.c_str());
+			exit(1);
+		}
+	}
+
+	if ( what == 0 ) {
+		printf("please use correct format:\n%s", sFormat.c_str());
+		return -1;
+	}
+
+	argc = 2;
+
+	switch ( what )
+	{
+	case 1:
+		argv[1] = (char*) CHOOSER_MODE;
+		break;
+	case 2:
+		argv[1] = (char*) SHOW_TEST_FLAG;
+		break;
+	case 3:
+		argv[1] = (char*) SHOW_SUIT_FLAG;
+		break;
+	case 4:
+		argv[1] = (char*) RUN_TEST_FLAG;
+		break;
+	case 5:
+		argv[1] = (char*) RUN_SUIT_FLAG;
+		break;
+	default:
+		printf("please use correct format:\n%s", sFormat.c_str());
+		exit(1);
+	}
+
+	testmanager = TestManager::GetInstance(nat_mem_type.c_str());
+
+	string sControlFlag = argv[1];
+
+	if (sControlFlag.compare(CHOOSER_MODE) == 0) {
+		result = chooserMode();
+	} else {
+		result = scriptMode(argc, argv);
+	}
+	return result;
+}//main
+
+////////////////////////////////////////////////////////////////////
+

+ 64 - 0
kernel-tests/run.sh

@@ -0,0 +1,64 @@
+#! /bin/sh
+
+# Copyright (c) 2014,2017,2021, The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of The Linux Foundation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -e
+./test_env_setup.sh
+
+echo "Starting test"
+
+if [ $# -eq 0 ]; then
+	echo "No args\n"
+	exec ./ipa_kernel_tests --suite_name Regression
+fi
+
+#Parse the args for valid switches
+while [ $# -gt 0 ]; do
+    case $1 in
+	-n | --nominal)
+		echo "Nominal\n"
+		exec ./ipa_kernel_tests --suite_name Regression
+		exit 0
+		;;
+	-a | --adversarial)
+		echo "adversarial\n"
+		echo "Currently no adversarial tests"
+		exit 0
+		;;
+	-r | --repeatability)
+		echo "Currently no repeatability tests"
+	-s | --stress)
+		echo "Currently no stress tests"
+		exit 0
+		;;
+	-h | --help | *)
+		echo "Usage: ./run.sh -[n][a][r][s]"
+		exit 1
+		;;
+        esac
+done