Browse Source

ipa-kernel-tests: ULSO tests, HPC based header insertion tests

Unit tests for the IPv5 ULSO feature and for HPC based
header insertion feature.

Change-Id: I312b135f33486c1171a355a69e6631764d021947
Acked-by: Eliad Ben Yishay <[email protected]>
Signed-off-by: Ilia Lin <[email protected]>
Ilia Lin 3 years ago
parent
commit
15ae40cd76

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

@@ -23,6 +23,9 @@ enum {
 	IPA_TEST_IOCTL_HOLB_CONFIG,
 	IPA_TEST_IOCTL_FLT_TBL_IN_SRAM,
 	IPA_TEST_IOCTL_GET_MEM_PART,
+	IPA_TEST_IOCTL_ULSO_CONFIGURE,
+	IPA_TEST_IOCTL_ADD_HDR_HPC,
+	IPA_TEST_IOCTL_PKT_INIT_EX_SET_HDR_OFST,
 	IPA_TEST_IOCTL_NUM,
 };
 
@@ -47,6 +50,15 @@ enum {
 #define IPA_TEST_IOC_GET_MEM_PART _IOWR(IPA_TEST_IOC_MAGIC, \
 		IPA_TEST_IOCTL_GET_MEM_PART, \
 		struct ipa_test_mem_partition *)
+#define IPA_TEST_IOC_ULSO_CONFIGURE _IOWR(IPA_TEST_IOC_MAGIC, \
+		IPA_TEST_IOCTL_ULSO_CONFIGURE, \
+		struct ipa_test_config_header *)
+#define IPA_TEST_IOC_ADD_HDR_HPC _IOWR(IPA_TEST_IOC_MAGIC, \
+		IPA_TEST_IOCTL_ADD_HDR_HPC, \
+		struct ipa_ioc_add_hdr *)
+#define IPA_TEST_IOC_PKT_INIT_EX_SET_HDR_OFST _IOWR(IPA_TEST_IOC_MAGIC, \
+		IPA_TEST_IOCTL_PKT_INIT_EX_SET_HDR_OFST, \
+		struct ipa_ioc_set_pkt_init_ex_hdr_ofst *)
 
 #define IPA_TEST_CONFIG_MARKER 0x57
 #define IPA_TEST_CHANNEL_CONFIG_MARKER 0x83

+ 178 - 43
drivers/platform/msm/ipa/ipa_test_module/ipa_test_module_impl.c

@@ -57,7 +57,10 @@
 
 #define RX_NUM_BUFFS 16
 #define RX_SZ 32768
-#define RX_BUFF_SIZE ((RX_SZ)/(RX_NUM_BUFFS))
+/* Lowest power of 2 that is bigger than what is used in Ulso test */
+#define MAX_ULSO_SEGMENT_SZ 16384
+#define RX_SZ_ULSO ((MAX_ULSO_SEGMENT_SZ) * (RX_NUM_BUFFS))
+#define RX_BUFF_SIZE ((rx_size)/(RX_NUM_BUFFS))
 
 #define IPA_TEST_DMUX_HEADER_LENGTH           8
 #define IPA_TEST_META_DATA_IS_VALID           1
@@ -110,6 +113,7 @@ struct device *ipa_get_pdev(void);
 enum fops_type {
 	IPA_TEST_REG_CHANNEL,
 	IPA_TEST_DATA_PATH_TEST_CHANNEL,
+	IPA_TEST_ULSO_DATA_PATH_TEST_CHANNEL,
 	MAX_FOPS
 };
 
@@ -225,6 +229,8 @@ struct ipa_tx_suspend_private_data {
 
 static struct test_context *ipa_test;
 
+static size_t rx_size;
+
 
 /**
  * Allocate memory from system memory.
@@ -472,13 +478,22 @@ static ssize_t set_skb_for_user(struct file *filp, char __user *buf,
 static ssize_t get_skb_from_user(struct file *filp, const char __user *buf,
 		       size_t size, loff_t *f_pos);
 
+static ssize_t get_ulso_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,
+	.read = set_skb_for_user,
 	.write = get_skb_from_user,
 };
 
+static const struct file_operations ulso_data_path_fops = {
+	.owner = THIS_MODULE,
+	.open = channel_open,
+	.read = set_skb_for_user,
+	.write = get_ulso_skb_from_user,
+};
 
 /*
  * This will create the char device named
@@ -566,6 +581,9 @@ int create_channel_device_by_type(
 	case IPA_TEST_DATA_PATH_TEST_CHANNEL:
 		cdev_init(&channel_dev->cdev, &data_path_fops);
 		break;
+	case IPA_TEST_ULSO_DATA_PATH_TEST_CHANNEL:
+		cdev_init(&channel_dev->cdev, &ulso_data_path_fops);
+		break;
 	default:
 		IPATEST_ERR("Wrong fops type");
 		ret = -EINVAL;
@@ -632,6 +650,8 @@ struct datapath_ctx {
 
 struct datapath_ctx *p_data_path_ctx;
 
+bool init_write_done_completion;
+
 
 /*
  * Inits the kfifo needed for the
@@ -640,6 +660,7 @@ struct datapath_ctx *p_data_path_ctx;
 int datapath_ds_init(void)
 {
 	int res = 0;
+	rx_size = RX_SZ;
 
 	p_data_path_ctx = kzalloc(sizeof(struct datapath_ctx), GFP_KERNEL);
 	if (!p_data_path_ctx) {
@@ -696,6 +717,24 @@ static struct sk_buff *datapath_create_skb(const char *buf, size_t size)
 	return skb;
 }
 
+static struct sk_buff *ulso_create_skb(const char *buf, size_t size)
+{
+	struct sk_buff *skb;
+
+	IPATEST_DBG("Entering\n");
+
+	skb = datapath_create_skb(buf, size);
+	if (unlikely(!skb))
+		return NULL;
+
+	/* Mark the skb as gso skb */
+	skb_increase_gso_size(skb_shinfo(skb), 1);
+
+	IPATEST_DBG("Exiting\n");
+
+	return skb;
+}
+
 static int datapath_read_data(void *element, int size)
 {
 	int res;
@@ -796,6 +835,45 @@ static ssize_t get_skb_from_user(struct file *filp, const char __user *buf,
 	return size;
 }
 
+/*
+ * 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_ulso_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 = ulso_create_skb(buf, size);
+	if (!skb)
+		return -EINVAL;
+
+	if (!init_write_done_completion) {
+		init_completion(&p_data_path_ctx->write_done_completion);
+		init_write_done_completion = true;
+	} else {
+		reinit_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
@@ -2806,19 +2884,14 @@ 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]);
+		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]);
+		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;
 	}
 }
@@ -4069,7 +4142,8 @@ static ssize_t ipa_test_read(struct file *filp,
 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)
+static int configure_app_to_ipa_path(struct ipa_channel_config __user *to_ipa_user,
+	bool isUlso)
 {
 	int retval;
 	struct ipa_channel_config to_ipa_channel_config = {0};
@@ -4106,14 +4180,12 @@ static int configure_app_to_ipa_path(struct ipa_channel_config __user *to_ipa_us
 	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) {
+	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) {
+	if (to_ipa_channel_config.tail_marker != IPA_TEST_CHANNEL_CONFIG_MARKER) {
 		IPATEST_ERR("bad tail_marker - possible memory corruption\n");
 		return -EFAULT;
 	}
@@ -4126,39 +4198,37 @@ static int configure_app_to_ipa_path(struct ipa_channel_config __user *to_ipa_us
 	}
 
 	/* Channel from which the userspace shall communicate to this pipe */
-	retval = create_channel_device(index, "to_ipa",
-				&to_ipa_devs[index], TX_SZ);
+	if(isUlso){
+		retval = create_channel_device_by_type(index, "to_ipa", &to_ipa_devs[index], TX_SZ,
+		IPA_TEST_ULSO_DATA_PATH_TEST_CHANNEL);
+	} else {
+		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];
+	ipa_test->tx_channels[ipa_test->num_tx_channels++] = to_ipa_devs[index];
+	if (isUlso)
+	    return 0;
 
 	/* 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);
+	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)) {
+	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);
+	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;
@@ -4167,7 +4237,7 @@ static int configure_app_to_ipa_path(struct ipa_channel_config __user *to_ipa_us
 	return 0;
 }
 
-static int configure_app_from_ipa_path(struct ipa_channel_config __user *from_ipa_user)
+static int configure_app_from_ipa_path(struct ipa_channel_config __user *from_ipa_user, bool isUlso)
 {
 	int retval;
 	struct ipa_channel_config from_ipa_channel_config = {0};
@@ -4227,7 +4297,7 @@ static int configure_app_from_ipa_path(struct ipa_channel_config __user *from_ip
 
 	/* Channel from which the userspace shall communicate to this pipe */
 	retval = create_channel_device(index, "from_ipa",
-			&from_ipa_devs[index], RX_SZ);
+			&from_ipa_devs[index], rx_size);
 	if (retval) {
 		IPATEST_ERR("channel device creation error\n");
 		return -1;
@@ -4238,6 +4308,9 @@ static int configure_app_from_ipa_path(struct ipa_channel_config __user *from_ip
 	/* Connect IPA --> Apps */
 	IPATEST_DBG("copying from 0x%px\n", from_ipa_channel_config.cfg);
 	memset(&sys_in, 0, sizeof(sys_in));
+	if (isUlso) {
+		sys_in.notify = notify_ipa_write_done;
+	}
 	sys_in.client = from_ipa_channel_config.client;
 	retval = copy_from_user(
 		&sys_in.ipa_ep_cfg,
@@ -4269,7 +4342,8 @@ static int configure_app_from_ipa_path(struct ipa_channel_config __user *from_ip
 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)
+		struct ipa_channel_config **to_ipa_channel_config_array,
+		bool isUlso)
 {
 	int retval;
 	int i;
@@ -4307,14 +4381,19 @@ static int configure_test_scenario(
 
 	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]);
+		retval = configure_app_from_ipa_path(from_ipa_channel_config_array[i], isUlso);
 		if (retval) {
 			IPATEST_ERR("fail to configure from_ipa_%d", i);
 			goto fail;
 		}
 	}
 
+	if (isUlso) {
+		rx_size = RX_SZ_ULSO;
+	} else {
+		rx_size = RX_SZ;
+	}
+
 	retval = insert_descriptors_into_rx_endpoints(RX_BUFF_SIZE);
 	if (retval) {
 		IPATEST_ERR("RX descriptors failed\n");
@@ -4323,8 +4402,7 @@ static int configure_test_scenario(
 	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]);
+		retval = configure_app_to_ipa_path(to_ipa_channel_config_array[i], isUlso);
 		if (retval) {
 			IPATEST_ERR("fail to configure to_ipa_%d", i);
 			goto fail;
@@ -4346,7 +4424,55 @@ fail:
 	return retval;
 }
 
-static int handle_configuration_ioctl(unsigned long ioctl_arg)
+static int handle_add_hdr_hpc(unsigned long ioctl_arg)
+{
+    struct ipa_ioc_add_hdr hdrs;
+    struct ipa_hdr_add *hdr;
+    int retval;
+
+	IPATEST_ERR("copying from 0x%px\n", (u8 *)ioctl_arg);
+	retval = copy_from_user(&hdrs, (u8 *)ioctl_arg, sizeof(hdrs) + sizeof(*hdr));
+	if (retval) {
+			IPATEST_ERR("failing copying header from user\n");
+			return retval;
+	}
+    retval = ipa3_add_hdr_hpc(&hdrs);
+    if (retval) {
+        IPATEST_ERR("ipa3_add_hdr_hpc failed\n");
+        return retval;
+    }
+	IPATEST_ERR("ELIAD: \n");
+	hdr = &hdrs.hdr[0];
+    if (hdr->status) {
+        IPATEST_ERR("ipa3_add_hdr_hpc failed\n");
+        return hdr->status;
+    }
+	IPATEST_ERR("ELIAD: \n");
+    if (copy_to_user((void __user *)ioctl_arg, &hdrs, sizeof(hdrs) + sizeof(*hdr))) {
+        retval = -EFAULT;
+    }
+	IPATEST_ERR("ELIAD: \n");
+
+    return 0;
+}
+
+static int handle_pkt_init_ex_set_hdr_ofst_ioctl(unsigned long ioctl_arg)
+{
+	struct ipa_pkt_init_ex_hdr_ofst_set hdr_ofst;
+	int retval;
+
+	IPATEST_DBG("copying from 0x%px\n", (u8 *)ioctl_arg);
+	retval = copy_from_user(&hdr_ofst, (u8 *)ioctl_arg, sizeof(hdr_ofst));
+	if (retval) {
+			IPATEST_ERR("failing copying header from user\n");
+			return retval;
+	}
+
+	return ipa_set_pkt_init_ex_hdr_ofst(&hdr_ofst, true);
+}
+
+static int handle_configuration_ioctl(unsigned long ioctl_arg,
+	bool isUlso)
 {
 	int retval;
 	int needed_bytes;
@@ -4405,10 +4531,10 @@ static int handle_configuration_ioctl(unsigned long ioctl_arg)
 		goto fail_copy_to;
 	}
 
-	retval = configure_test_scenario(
-			&test_header,
+	retval = configure_test_scenario(&test_header,
 			from_ipa_channel_config_array,
-			to_ipa_channel_config_array);
+			to_ipa_channel_config_array,
+			isUlso);
 	if (retval)
 		IPATEST_ERR("fail to configure the system\n");
 
@@ -4569,7 +4695,7 @@ static long ipa_test_ioctl(struct file *filp,
 
 	switch (cmd) {
 	case IPA_TEST_IOC_CONFIGURE:
-		retval = handle_configuration_ioctl(arg);
+		retval = handle_configuration_ioctl(arg, false);
 		break;
 
 	case IPA_TEST_IOC_CLEAN:
@@ -4593,6 +4719,15 @@ static long ipa_test_ioctl(struct file *filp,
 	case IPA_TEST_IOC_GET_MEM_PART:
 		retval = ipa_test_get_mem_part(arg);
 		break;
+	case IPA_TEST_IOC_ULSO_CONFIGURE:
+		retval = handle_configuration_ioctl(arg, true);
+		break;
+    case IPA_TEST_IOC_ADD_HDR_HPC:
+		retval = handle_add_hdr_hpc(arg);
+		break;
+	case IPA_TEST_IOC_PKT_INIT_EX_SET_HDR_OFST:
+		retval = handle_pkt_init_ex_set_hdr_ofst_ioctl(arg);
+		break;
 	default:
 		IPATEST_ERR("ioctl is not supported (%d)\n", cmd);
 		return -ENOTTY;

+ 90 - 0
kernel-tests/HeaderInsertion.cpp

@@ -31,8 +31,11 @@
 #include <sys/ioctl.h>
 #include <fcntl.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <cstring>
 
 #include "HeaderInsertion.h"
+#include "TestsUtils.h"
 
 /*All interaction through the driver are
  * made through this inode.
@@ -76,6 +79,50 @@ bool HeaderInsertion::AddHeader(struct ipa_ioc_add_hdr *pHeaderTableToAdd)
 	return (-1 != nRetVal);
 }
 
+bool HeaderInsertion::addHeaderHpc(const string& name, uint8_t* header, const size_t headerLen, bool isPartial, enum ipa_client_type ipaClient){
+	if(name.empty() || name.size() >= IPA_RESOURCE_NAME_MAX){
+		return false;
+	}
+	int fd = open(CONFIGURATION_NODE_PATH, O_RDONLY);
+	if (fd < 0) {
+		cout << "failed to open " << CONFIGURATION_NODE_PATH << endl;
+		return false;
+	}
+	struct ipa_ioc_add_hdr *iocH = static_cast<struct ipa_ioc_add_hdr*>(calloc(1, sizeof(*iocH) + sizeof(struct ipa_hdr_add)));
+	if(!iocH){
+		return false;
+	}
+	iocH->commit = 1;
+	iocH->num_hdrs = 1;
+	struct ipa_hdr_add *h = &iocH->hdr[0];
+	strlcpy(h->name, name.c_str(), IPA_RESOURCE_NAME_MAX);
+	memcpy(h->hdr, header, headerLen);
+	h->hdr_len = headerLen;
+	h->hdr_hdl = -1;
+	h->status = -1;
+	h->is_partial = isPartial;
+	cout << "h->name=" << h->name << ", h->is_partial=" << h->is_partial << endl;
+	int result = ioctl(fd, IPA_TEST_IOC_ADD_HDR_HPC, iocH);
+	if(result || h->status){
+		free(iocH);
+		close(fd);
+		return false;
+	}
+	cout << "result=" << result << ", status=" << h->status << ", ipaClient=" << ipaClient << endl;
+    struct ipa_pkt_init_ex_hdr_ofst_set lookup;
+    lookup.ep = ipaClient;
+    strlcpy(lookup.name, name.c_str(), IPA_RESOURCE_NAME_MAX);
+    result = ioctl(fd, IPA_TEST_IOC_PKT_INIT_EX_SET_HDR_OFST , &lookup);
+    if (result) {
+		free(iocH);
+		close(fd);
+		return false;
+    }
+	free(iocH);
+	close(fd);
+	return true;
+}
+
 bool HeaderInsertion::DeleteHeader(struct ipa_ioc_del_hdr *pHeaderTableToDelete)
 {
 	int nRetVal = 0;
@@ -85,6 +132,32 @@ bool HeaderInsertion::DeleteHeader(struct ipa_ioc_del_hdr *pHeaderTableToDelete)
 	return (-1 != nRetVal);
 }
 
+bool HeaderInsertion::DeleteHeader(const string& name){
+	if(name.empty() || name.size() >= IPA_RESOURCE_NAME_MAX){
+		return false;
+	}
+	int hdl = GetHeaderHandle(name);
+	if(hdl == -1){
+		return false;
+	}
+	struct ipa_ioc_del_hdr *iocD = static_cast<struct ipa_ioc_del_hdr*>(calloc(1, sizeof(*iocD) + sizeof(struct ipa_hdr_del)));
+	if(!iocD){
+		return false;
+	}
+	iocD->commit = 1;
+	iocD->num_hdls = 1;
+	struct ipa_hdr_del *h = &iocD->hdl[0];
+	h->hdl = hdl;
+	h->status = -1;
+	cout << "h->hdl=" << h->hdl << endl;
+	if(!DeleteHeader(iocD)){
+		free(iocD);
+		return false;
+	}
+	free(iocD);
+	return true;
+}
+
 bool HeaderInsertion::AddProcCtx(struct ipa_ioc_add_hdr_proc_ctx *procCtxTable)
 {
 	int retval = 0;
@@ -154,6 +227,23 @@ bool HeaderInsertion::GetHeaderHandle(struct ipa_ioc_get_hdr *pHeaderStruct)
 	return true;
 }
 
+int HeaderInsertion::GetHeaderHandle(const string& name){
+	if(name.empty() || name.size() >= IPA_RESOURCE_NAME_MAX){
+		return false;
+	}
+	struct ipa_ioc_get_hdr retHeader;
+	memset(&retHeader, 0, sizeof(retHeader));
+	strlcpy(retHeader.name, name.c_str(), IPA_RESOURCE_NAME_MAX);
+	retHeader.hdl = -1;
+	printf("retHeader.name=%s\n", retHeader.name);
+	if(!GetHeaderHandle(&retHeader)){
+		cout << "GetHeaderHandle(&retHeader) Failed" << endl;
+		return -1;
+	}
+	cout << "retHeader.hdl=" << retHeader.hdl << endl;
+	return retHeader.hdl;
+}
+
 bool HeaderInsertion::CopyHeader(struct ipa_ioc_copy_hdr *pCopyHeaderStruct)
 {
 	int retval = 0;

+ 11 - 0
kernel-tests/HeaderInsertion.h

@@ -31,7 +31,15 @@
 #define HEADER_INSERTION_H_
 
 #include <stdint.h>
+#include <string>
+#include <iostream>
 #include "linux/msm_ipa.h"
+#include "ipa_test_module.h"
+#include "Constants.h"
+
+using std::string;
+using std::cout;
+using std::endl;
 
 class HeaderInsertion
 {
@@ -40,8 +48,11 @@ private:
 
 public:
 	bool AddHeader(struct ipa_ioc_add_hdr *pHeaderTable);
+	bool addHeaderHpc(const string& name, uint8_t* header, const size_t headerLen, bool isPartial, enum ipa_client_type ipaClient);
 	bool DeleteHeader(struct ipa_ioc_del_hdr *pHeaderTable);
+	bool DeleteHeader(const string& name);
 	bool GetHeaderHandle(struct ipa_ioc_get_hdr *pHeaderStruct);
+	int GetHeaderHandle(const string& name);
 	bool CopyHeader(struct ipa_ioc_copy_hdr *pCopyHeaderStruct);
 
 	// Processing context

+ 31 - 3
kernel-tests/InterfaceAbstraction.cpp

@@ -30,10 +30,14 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <iostream>
 #include "InterfaceAbstraction.h"
 
 #define MAX_OPEN_RETRY 10000
 
+using std::cout;
+using std::endl;
+
 bool InterfaceAbstraction::Open(const char * toIPAPath, const char * fromIPAPath)
 {
 	int tries_cnt = MAX_OPEN_RETRY;
@@ -95,9 +99,9 @@ void InterfaceAbstraction::Close()
 	close(m_fromIPADescriptor);
 }
 
-bool InterfaceAbstraction::SendData(unsigned char *buf, size_t size)
+long InterfaceAbstraction::SendData(unsigned char *buf, size_t size)
 {
-	int bytesWritten = 0;
+	long bytesWritten = 0;
 
 	printf("Trying to write %zu bytes to %d.\n", size, m_toIPADescriptor);
 
@@ -118,7 +122,7 @@ bool InterfaceAbstraction::SendData(unsigned char *buf, size_t size)
 		exit(-1);
 	}
 
-	printf("bytesWritten = %d.\n", bytesWritten);
+	cout << "bytesWritten = " << bytesWritten << endl;
 
 	return bytesWritten;
 }
@@ -145,6 +149,30 @@ int InterfaceAbstraction::ReceiveData(unsigned char *buf, size_t size)
 	return totalBytesRead;
 }
 
+int InterfaceAbstraction::ReceiveSingleDataChunk(unsigned char *buf, size_t size){
+	size_t bytesRead = 0;
+	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);
+	return bytesRead;
+}
+
+int InterfaceAbstraction::setReadNoBlock(){
+	int flags = fcntl(m_fromIPADescriptor, F_GETFL, 0);
+	if(flags == -1){
+		return -1;
+	}
+	return fcntl(m_fromIPADescriptor, F_SETFL, flags | O_NONBLOCK);
+}
+
+int InterfaceAbstraction::clearReadNoBlock(){
+	int flags = fcntl(m_fromIPADescriptor, F_GETFL, 0);
+	if(flags == -1){
+		return -1;
+	}
+	return fcntl(m_fromIPADescriptor, F_SETFL, flags & ~O_NONBLOCK);
+}
+
 InterfaceAbstraction::~InterfaceAbstraction()
 {
 	close(m_fromIPADescriptor);

+ 4 - 1
kernel-tests/InterfaceAbstraction.h

@@ -45,8 +45,11 @@ public:
 	~InterfaceAbstraction();
 	bool Open(const char *toIPAPath, const char *fromIPAPath);
 	void Close();
-	bool SendData(unsigned char *buffer, size_t size);
+	long SendData(unsigned char *buffer, size_t size);
 	int ReceiveData(unsigned char *buf, size_t size);
+	int ReceiveSingleDataChunk(unsigned char *buf, size_t size);
+	int setReadNoBlock();
+	int clearReadNoBlock();
 
 	string m_toChannelName;
 	string m_fromChannelName;

+ 1 - 0
kernel-tests/Makefile.am

@@ -48,4 +48,5 @@ ipa_kernel_tests_SOURCES =\
 		FilteringEthernetBridgingTests.cpp \
 		NatTest.cpp \
 		IPv6CTTest.cpp \
+		UlsoTest.cpp \
 		main.cpp

+ 9 - 7
kernel-tests/TestsUtils.cpp

@@ -992,18 +992,16 @@ static bool is_reconfigure_required(struct ipa_test_config_header *header)
 	return false;
 }
 
-int GenericConfigureScenario(struct ipa_test_config_header *header)
+int GenericConfigureScenario(struct ipa_test_config_header *header, bool isUlso)
 {
 	int fd;
 	int retval;
 
 	if (is_reconfigure_required(header) == false) {
-		g_Logger.AddMessage(LOG_DEVELOPMENT ,
-			"No need to reconfigure, we are all good :)\n");
+		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 , "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);
@@ -1047,7 +1045,7 @@ int GenericConfigureScenario(struct ipa_test_config_header *header)
 				header->to_ipa_channel_config[i]->en_status);
 	}
 
-	fd = open(CONFIGURATION_NODE_PATH,  O_RDWR);
+	fd = open(CONFIGURATION_NODE_PATH, O_RDWR);
 	if (fd == -1) {
 		g_Logger.AddMessage(LOG_ERROR,
 				"%s - open %s failed (fd=%d,errno=%s)\n",
@@ -1055,7 +1053,11 @@ int GenericConfigureScenario(struct ipa_test_config_header *header)
 		return false;
 	}
 
-	retval = ioctl(fd, IPA_TEST_IOC_CONFIGURE, header);
+	if(isUlso){
+		retval = ioctl(fd, IPA_TEST_IOC_ULSO_CONFIGURE, header);
+	} else {
+		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);

+ 10 - 4
kernel-tests/TestsUtils.h

@@ -296,7 +296,8 @@ bool CreateBypassRoutingTable_v2(
 */
 void ConfigureScenario(int testConfiguration);
 void ConfigureScenario(int testConfiguration, const char *params);
-int GenericConfigureScenario(struct ipa_test_config_header *header);
+int GenericConfigureScenario(struct ipa_test_config_header *header,
+		bool isUlso=false);
 int GenericConfigureScenarioDestory(void);
 int ConfigureSystem(int testConfiguration, int fd);
 int ConfigureSystem(int testConfiguration, int fd, const char *params);
@@ -696,6 +697,11 @@ struct ipa_ep_cfg_seq {
 	int seq_type;
 };
 
+struct ipa_ep_cfg_ulso {
+	int ipid_min_max_idx;
+	bool is_ulso_pipe;
+};
+
 struct ipa_ep_cfg_holb {
 	uint32_t tmr_val;
 	uint32_t base_val;
@@ -705,9 +711,9 @@ struct ipa_ep_cfg_holb {
 	uint8_t scaled_time;
 };
 
-struct ipa_ep_cfg_ulso {
-	int ipid_min_max_idx;
-	bool is_ulso_pipe;
+struct ipa_pkt_init_ex_hdr_ofst_set {
+	char name[IPA_RESOURCE_NAME_MAX];
+	enum ipa_client_type ep;
 };
 
 /*

+ 396 - 0
kernel-tests/UlsoTest.cpp

@@ -0,0 +1,396 @@
+/*
+ * 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.
+ */
+#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 "UlsoTestFixture.h"
+#include "HeaderInsertion.h"
+
+#define ARRAY_SIZE(A) (sizeof(ArraySizeHelper(A)))
+
+template <typename T, size_t N>
+char (&ArraySizeHelper(T (&a)[N]))[N];
+
+using std::cout;
+using std::endl;
+using std::string;
+
+using I4 = IPv4Header;
+using I6 = IPv6Header;
+using UDPH = UdpHeader;
+using TCPH = TcpHeader;
+
+/* Packet modification function objects */
+template<typename PacketType> class PacketModifier {public:virtual void operator()(PacketType& p) const = 0;};
+template<typename PacketType> class NullPacketModifier: public PacketModifier<PacketType> {public:void operator()(PacketType& p) const override {}};
+template<typename PacketType> class ZeroChecksumPacketModifier: public PacketModifier<PacketType>
+	{public:void operator()(PacketType& p) const override {p.mQmapHeader.setmZeroChecksum(1);}};
+template<typename PacketType> class OutOfBoundsPacketModifier: public PacketModifier<PacketType>
+	{public:void operator()(PacketType& p) const override {p.mQmapHeader.setmIpIdCfg(0);p.setIpId(65530);}};
+
+template<typename Transport, typename Internet, const size_t* SegmentSizesArr, size_t SegmentSizesArrSize, const float* SegmentsNumsArr,
+	size_t SegmentsNumsArrSize, typename Modifier = NullPacketModifier<UlsoPacket<Transport, Internet>>>
+class PacketsGeneratorClass {
+
+protected:
+
+	using PacketType = UlsoPacket<Transport, Internet>;
+
+public:
+
+	vector<PacketType> operator()(){
+		vector<PacketType> outVec;
+		Modifier m;
+		for(size_t i=0; i<SegmentSizesArrSize; i++){
+			for(size_t j=0; j<SegmentsNumsArrSize; j++){
+				PacketType p(SegmentSizesArr[i], static_cast<size_t>(SegmentSizesArr[i] * SegmentsNumsArr[j]), true);
+				m(p);
+				outVec.emplace_back(p);
+			}
+		}
+		return outVec;
+	}
+};
+
+template<typename Transport, typename Internet, typename PacketsGenerator>
+class UlsoTest: public UlsoTestFixture {
+
+private:
+
+	using PacketType = UlsoPacket<Transport, Internet>;
+
+	bool singlePacketRun(PacketType& p){
+		memset(m_sendBuf, 0, sizeof(m_sendBuf));
+		size_t packetSize = p.asArray(m_sendBuf);
+		size_t numSent = m_producer.SendData(m_sendBuf, packetSize);
+
+		if(numSent == 0){
+			return false;
+		}
+		vector<PacketType> segmentedPacketsVec = p.segment();
+		for(auto& segmentedPacket: segmentedPacketsVec){
+			memset(m_receiveBuf, 0, sizeof(m_receiveBuf));
+			memset(m_segmentBuf, 0, sizeof(m_segmentBuf));
+			packetSize = segmentedPacket.asArray(m_segmentBuf);
+			size_t recievedBytes = m_consumer.ReceiveSingleDataChunk(m_receiveBuf, packetSize);
+			if(packetSize != recievedBytes || memcmp(m_segmentBuf, m_receiveBuf, packetSize)){
+				return fail(numSent, packetSize, recievedBytes);
+			}
+		}
+		return clearPipe() == 0;
+	}
+
+public:
+
+	UlsoTest(const char* name){
+		m_name = name;
+		string title = string("ULSO Test");
+		string packetStructure = string("Structure: ") + string ("QMAP + Ethernet 2 + ")
+			+ string(Internet().name()) + string(" ") + string(Transport().name());
+		string testProcess = string(
+			"1. Config IPA->APPS test pipe\n"
+			"2. Generate a vector of ULSO packets\n"
+			"3. For each packet in the packets vector\n"
+			"	a. Send the packet over the APPS->IPA pipe using ipa_tx_dp\n"
+			"	b. Segment the packet using the software simulation and store it in a segments vector\n"
+			"	c. For each segment in the segments vector in order\n"
+			"		# Receive a segment over IPA->APPS test pipe\n"
+			"		# Compare the received segment to the software simulated segment\n"
+			"4. Clear the IPA->USB pipe and verify there were no bytes left in the pipe");
+		m_description = string(title + "\n" + packetStructure + "\n" + testProcess + "\n").c_str();
+		m_minIPAHwType = IPA_HW_v5_0;
+		Register(*this);
+	}
+
+	virtual bool Run() override {
+		vector<PacketType> packetsVec = PacketsGenerator()();
+		for(auto& p: packetsVec){
+			if(!singlePacketRun(p)){
+				cout << "Failed With the following packet:" << endl;
+				cout << p << endl;
+				return false;
+			}
+		}
+		return true;
+	}
+};
+
+template<typename Transport, typename Internet, typename PacketsGenerator>
+class UlsoHPCTest: public UlsoTestFixture {
+
+private:
+
+	using PacketType = UlsoPacket<Transport, Internet>;
+	static constexpr size_t rndisHdrLen {44};
+	HeaderInsertion m_HeaderInsertion;
+	uint8_t mRndisHeader[rndisHdrLen] = {0};
+
+	bool fail(size_t sendSize=0, size_t totalSegmentsSize=0, size_t recievedBytes=0){
+		printBuf(m_sendBuf, sendSize, "Sent:");
+		printBuf(m_receiveBuf, recievedBytes, string("Rceived ")
+				+ std::to_string(recievedBytes) + string(" Bytes:"));
+		printBuf(m_segmentBuf, totalSegmentsSize, string("Expected to receive ")
+			+ std::to_string(totalSegmentsSize) + string(" Bytes:"));
+		clearPipe();
+		return false;
+	}
+
+	bool singlePacketRun(PacketType& p){
+		cout << p << endl;
+		memset(m_sendBuf, 0, sizeof(m_sendBuf));
+		size_t sendSize = p.asArray(m_sendBuf);
+		if(!m_producer.SendData(m_sendBuf, sendSize)){
+			return fail(sendSize);
+		}
+		vector<PacketType> segmentedPacketsVec = p.segment();
+		memset(m_segmentBuf, 0, sizeof(m_segmentBuf));
+		uint8_t *segmentBufPtr = m_segmentBuf;
+		size_t totalSegmentsSize = 0;
+		vector<size_t> comparisionIntervalsSizesVec;
+		for(auto& segmentedPacket: segmentedPacketsVec){
+			memcpy(segmentBufPtr, mRndisHeader, sizeof(mRndisHeader));
+			segmentBufPtr += sizeof(mRndisHeader);
+			comparisionIntervalsSizesVec.emplace_back(sizeof(mRndisHeader));
+			totalSegmentsSize += sizeof(mRndisHeader);
+			size_t n = segmentedPacket.asArray(segmentBufPtr);
+			segmentBufPtr += n;
+			totalSegmentsSize += n;
+			comparisionIntervalsSizesVec.emplace_back(n);
+		}
+		memset(m_receiveBuf, 0, sizeof(m_receiveBuf));
+		size_t recievedBytes = m_consumer.ReceiveSingleDataChunk(m_receiveBuf, totalSegmentsSize);
+		if(totalSegmentsSize != recievedBytes){
+			return fail(sendSize, totalSegmentsSize, recievedBytes);
+		}
+		segmentBufPtr = m_segmentBuf;
+		uint8_t *recieveBufPtr = m_receiveBuf;
+		while(!comparisionIntervalsSizesVec.empty()){
+			size_t skipSize = comparisionIntervalsSizesVec.front();
+			recieveBufPtr += skipSize;
+			segmentBufPtr += skipSize;
+			comparisionIntervalsSizesVec.erase(comparisionIntervalsSizesVec.begin());
+			if(comparisionIntervalsSizesVec.empty()){
+				return fail(sendSize, totalSegmentsSize, recievedBytes);
+			}
+			size_t compareSize = comparisionIntervalsSizesVec.front();
+			if(memcmp(segmentBufPtr, recieveBufPtr, compareSize)){
+				return fail(sendSize, totalSegmentsSize, recievedBytes);
+			}
+			segmentBufPtr += compareSize;
+			recieveBufPtr += compareSize;
+			comparisionIntervalsSizesVec.erase(comparisionIntervalsSizesVec.begin());
+		}
+		if(clearPipe()){
+			return fail(sendSize, totalSegmentsSize, recievedBytes);
+		}
+		return true;
+	}
+
+protected:
+
+	virtual void configFromEp(struct test_ipa_ep_cfg *ep_cfg){
+		ep_cfg->hdr.hdr_len = ETH_HLEN + rndisHdrLen;
+		ep_cfg->hdr.hdr_additional_const_len = ETH_HLEN;
+		ep_cfg->hdr.hdr_ofst_pkt_size_valid = true;
+		ep_cfg->hdr.hdr_ofst_pkt_size = 3 * sizeof(uint32_t);
+		ep_cfg->hdr_ext.hdr_total_len_or_pad_offset = sizeof(uint32_t);
+		ep_cfg->hdr_ext.hdr_total_len_or_pad = IPA_HDR_TOTAL_LEN;
+		ep_cfg->hdr_ext.hdr_total_len_or_pad_valid = true;
+		ep_cfg->hdr_ext.hdr_little_endian = true;
+		ep_cfg->aggr.aggr_en = IPA_ENABLE_AGGR;
+		ep_cfg->aggr.aggr = IPA_GENERIC;
+		ep_cfg->aggr.aggr_byte_limit = 4;
+		ep_cfg->aggr.aggr_time_limit = 1000;
+	}
+
+public:
+
+	UlsoHPCTest(const char* name, const char* description){
+		m_name = name;
+		m_description = description;
+		m_minIPAHwType = IPA_HW_v5_0;
+		for(size_t i=0; i<rndisHdrLen; i++){
+			mRndisHeader[i] = i;
+		}
+		Register(*this);
+	}
+
+	virtual bool Run() override {
+		string headerName("rndis");
+		if(!m_HeaderInsertion.addHeaderHpc(headerName, mRndisHeader, rndisHdrLen, false, IPA_CLIENT_TEST_CONS)){
+			LOG_MSG_ERROR("!m_HeaderInsertion.addHeaderHpc(headerName, mRndisHeader, 44, false, true) Failed.");
+			return false;
+		}
+		vector<PacketType> packetsVec = PacketsGenerator()();
+		for(auto& p: packetsVec){
+			if(!singlePacketRun(p)){
+				return false;
+			}
+		}
+		if(!m_HeaderInsertion.DeleteHeader(headerName)){
+			LOG_MSG_ERROR("Delete rndis header failed");
+			return false;
+		}
+		return true;
+	}
+};
+
+/* Tests Macros */
+#define PACKETS_GEN_MODIFY(T, I, a, b, m) PacketsGeneratorClass<T, I, a, ARRAY_SIZE(a), b, ARRAY_SIZE(b), m<UlsoPacket<T, I>>>
+#define PACKETS_GEN(T, I, a, b) PACKETS_GEN_MODIFY(T, I, a, b, NullPacketModifier)//todo: change macro parameters to meaningfull names
+
+////////////////////////////////////////////////////////////////////////////////
+///////////            Simple Single Packet Tests                 //////////////
+////////////////////////////////////////////////////////////////////////////////
+/*
+ * Send a single packet and compare the received segments to the software simulation
+ */
+constexpr size_t segmentSizes1[] = {20};
+constexpr float segmentsNum1[] = {5};
+static UlsoTest<UDPH, I4, PACKETS_GEN(UDPH, I4, segmentSizes1, segmentsNum1)> ulsoTest0 {"Single Packet: IPV4 UDP"};
+static UlsoTest<TCPH, I4, PACKETS_GEN(TCPH, I4, segmentSizes1, segmentsNum1)> ulsoTest1 {"Single Packet: IPV4 TCP"};
+static UlsoTest<UDPH, I6, PACKETS_GEN(UDPH, I6, segmentSizes1, segmentsNum1)> ulsoTest2 {"Single Packet: IPV6 UDP"};
+static UlsoTest<TCPH, I6, PACKETS_GEN(TCPH, I6, segmentSizes1, segmentsNum1)> ulsoTest3 {"Single Packet: IPV6 TCP"};
+
+////////////////////////////////////////////////////////////////////////////////
+///////////         Segmentation & Non-Segmentation mix           //////////////
+////////////////////////////////////////////////////////////////////////////////
+/*
+ * Send a sequence of [large, small, large, small, ...] packets and compare the received segments to the software simulation
+ */
+constexpr size_t segmentSizes2[] = {10, 50, 100, 500, 1460};
+constexpr float segmentsNum2[] = {1, 4};
+static UlsoTest<UDPH, I4, PACKETS_GEN(UDPH, I4, segmentSizes2, segmentsNum2)> ulsoTest10 {"Segmentation No Segmentation IPV4 UDP"};
+static UlsoTest<TCPH, I4, PACKETS_GEN(TCPH, I4, segmentSizes2, segmentsNum2)> ulsoTest11 {"Segmentation No Segmentation IPV4 TCP"};
+static UlsoTest<UDPH, I6, PACKETS_GEN(UDPH, I6, segmentSizes2, segmentsNum2)> ulsoTest12 {"Segmentation No Segmentation IPV6 UDP"};
+static UlsoTest<TCPH, I6, PACKETS_GEN(TCPH, I6, segmentSizes2, segmentsNum2)> ulsoTest13 {"Segmentation No Segmentation IPV6 TCP"};
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////             Zero Checksum              ////////////////////
+////////////////////////////////////////////////////////////////////////////////
+/*
+ * Send a sequence of large packets with zero checksum=1 and compare the received segments to the software simulation
+ */
+constexpr size_t segmentSizes3[] = {10, 50, 100, 500, 1460};
+constexpr float numSegments3[] = {4};
+static UlsoTest<UDPH, I4, PACKETS_GEN_MODIFY(UDPH, I4, segmentSizes3, numSegments3, ZeroChecksumPacketModifier)>
+	ulsoTest20 {"Zero Checksum IPV4 UDP"};
+static UlsoTest<TCPH, I4, PACKETS_GEN_MODIFY(TCPH, I4, segmentSizes3, numSegments3, ZeroChecksumPacketModifier)>
+	ulsoTest21 {"Zero Checksum IPV4 TCP"};
+static UlsoTest<UDPH, I6, PACKETS_GEN_MODIFY(UDPH, I6, segmentSizes3, numSegments3, ZeroChecksumPacketModifier)>
+	ulsoTest22 {"Zero Checksum IPV6 UDP"};
+static UlsoTest<TCPH, I6, PACKETS_GEN_MODIFY(TCPH, I6, segmentSizes3, numSegments3, ZeroChecksumPacketModifier)>
+	ulsoTest23 {"Zero Checksum IPV6 TCP"};
+
+////////////////////////////////////////////////////////////////////////////////
+/////////        Segment Size Greater Than Payload Size        /////////////////
+////////////////////////////////////////////////////////////////////////////////
+/*
+ * Send a single packet with payload size and MSS matching an edge case and edge case and compare the received segments to the software simulation.
+ * Edge cases:
+ * 1. payload size < MSS ==> No segmentation
+ * 2. payload size == MSS - epsilon ==> No segmentation
+ * 3. payload size == MSS ==> Segmentation
+ */
+/* Segment Size = 100 Payload Size = 50 */
+constexpr size_t segmentSizes4[] = {100};
+constexpr float numSegments4[] = {0.5};
+static UlsoTest<UDPH, I4, PACKETS_GEN(UDPH, I4, segmentSizes4, numSegments4)> ulsoTest30 {"Payload Smaller Than MSS IPV4 UDP"};
+static UlsoTest<TCPH, I4, PACKETS_GEN(TCPH, I4, segmentSizes4, numSegments4)> ulsoTest31 {"Payload Smaller Than MSS IPV4 TCP"};
+static UlsoTest<UDPH, I6, PACKETS_GEN(UDPH, I6, segmentSizes4, numSegments4)> ulsoTest32 {"Payload Smaller Than MSS IPV6 UDP"};
+static UlsoTest<TCPH, I6, PACKETS_GEN(TCPH, I6, segmentSizes4, numSegments4)> ulsoTest33 {"Payload Smaller Than MSS IPV6 TCP"};
+
+/* Segment Size = 100 Payload Size = 99 */
+constexpr size_t segmentSizes5[] = {100};
+constexpr float numSegments5[] = {0.99};
+static UlsoTest<UDPH, I4, PACKETS_GEN(UDPH, I4, segmentSizes5, numSegments5)> ulsoTest40 {"Payload slightly Smaller Than MSS IPV4 UDP"};
+static UlsoTest<TCPH, I4, PACKETS_GEN(TCPH, I4, segmentSizes5, numSegments5)> ulsoTest41 {"Payload slightly Smaller Than MSS IPV4 TCP"};
+static UlsoTest<UDPH, I6, PACKETS_GEN(UDPH, I6, segmentSizes5, numSegments5)> ulsoTest42 {"Payload slightly Smaller Than MSS IPV6 UDP"};
+static UlsoTest<TCPH, I6, PACKETS_GEN(TCPH, I6, segmentSizes5, numSegments5)> ulsoTest43 {"Payload slightly Smaller Than MSS IPV6 TCP"};
+
+/* Segment Size = 20 Payload Size = 20 */
+constexpr size_t segmentSizes6[] = {100};
+constexpr float numSegments6[] = {1};
+static UlsoTest<UDPH, I4, PACKETS_GEN(UDPH, I4, segmentSizes6, numSegments6)> ulsoTest50 {"Payload Equals MSS IPV4 UDP"};
+static UlsoTest<TCPH, I4, PACKETS_GEN(TCPH, I4, segmentSizes6, numSegments6)> ulsoTest51 {"Payload Equals MSS IPV4 TCP"};
+static UlsoTest<UDPH, I6, PACKETS_GEN(UDPH, I6, segmentSizes6, numSegments6)> ulsoTest52 {"Payload Equals MSS IPV6 UDP"};
+static UlsoTest<TCPH, I6, PACKETS_GEN(TCPH, I6, segmentSizes6, numSegments6)> ulsoTest53 {"Payload Equals MSS IPV6 TCP"};
+
+////////////////////////////////////////////////////////////////////////////////
+//////////////             Valid Segment Sizes             /////////////////////
+////////////////////////////////////////////////////////////////////////////////
+/*
+ * Send a sequence of packets with different valid sizes and compare the received segments to the software simulation
+ */
+constexpr size_t segmentSizes7[] = {1460, 1220, 512, 1};
+static UlsoTest<UDPH, I4, PACKETS_GEN(UDPH, I4, segmentSizes7, segmentsNum1)> ulsoTest60 {"Valid Segment Sizes IPV4 UDP"};
+static UlsoTest<TCPH, I4, PACKETS_GEN(TCPH, I4, segmentSizes7, segmentsNum1)> ulsoTest61 {"Valid Segment Sizes IPV4 TCP"};
+static UlsoTest<UDPH, I6, PACKETS_GEN(UDPH, I6, segmentSizes7, segmentsNum1)> ulsoTest62 {"Valid Segment Sizes IPV6 UDP"};
+static UlsoTest<TCPH, I6, PACKETS_GEN(TCPH, I6, segmentSizes7, segmentsNum1)> ulsoTest63 {"Valid Segment Sizes IPV6 TCP"};
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////             Big Segment Sizes             /////////////////////
+////////////////////////////////////////////////////////////////////////////////
+/*
+ * Send a sequence of very large packets and compare the received segments to the software simulation
+ */
+constexpr size_t segmentSizes8[] = {2000, 3000, 4000, 5000, 6000, 10000};
+static UlsoTest<UDPH, I4, PACKETS_GEN(UDPH, I4, segmentSizes8, segmentsNum1)> ulsoTest70 {"Big Segment Sizes IPV4 UDP"};
+static UlsoTest<TCPH, I4, PACKETS_GEN(TCPH, I4, segmentSizes8, segmentsNum1)> ulsoTest71 {"Big Segment Sizes IPV4 TCP"};
+static UlsoTest<UDPH, I6, PACKETS_GEN(UDPH, I6, segmentSizes8, segmentsNum1)> ulsoTest72 {"Big Segment Sizes IPV6 UDP"};
+static UlsoTest<TCPH, I6, PACKETS_GEN(TCPH, I6, segmentSizes8, segmentsNum1)> ulsoTest73 {"Big Segment Sizes IPV6 TCP"};
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////        IP ID wrapp around min/max bounds        ///////////////
+////////////////////////////////////////////////////////////////////////////////
+/*
+ * Send a single packet such that:
+ * IPID + #segments < MAX IPID
+ * and compare the received segments to the software simulation
+ */
+constexpr size_t segmentSizes9[] = {2000};
+constexpr float numSegments9[] = {10};
+static UlsoTest<UDPH, I4, PACKETS_GEN_MODIFY(UDPH, I4, segmentSizes9, numSegments9, OutOfBoundsPacketModifier)> ulsoTest80 {"IPID CFG IPV4 UDP"};
+static UlsoTest<TCPH, I4, PACKETS_GEN_MODIFY(TCPH, I4, segmentSizes9, numSegments9, OutOfBoundsPacketModifier)> ulsoTest81 {"IPID CFG IPV4 UDP"};
+////////////////////////////////////////////////////////////////////////////////
+////////////////        HPC RNDIS Header Insertion        //////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+static UlsoHPCTest<UDPH, I4, PACKETS_GEN(UDPH, I4, segmentSizes1, segmentsNum1)> Ipv4UdpHpcRndisTest {"Ipv4UdpHpcRndisTest", "IPv4 + UDP"};
+static UlsoHPCTest<TCPH, I4, PACKETS_GEN(TCPH, I4, segmentSizes1, segmentsNum1)> Ipv4TcpHpcRndisTest {"Ipv4TcpHpcRndisTest", "IPv4 + TCP"};
+static UlsoHPCTest<UDPH, I6, PACKETS_GEN(UDPH, I6, segmentSizes1, segmentsNum1)> Ipv6UdpHpcRndisTest {"Ipv6UdpHpcRndisTest", "IPv6 + UDP"};
+static UlsoHPCTest<TCPH, I6, PACKETS_GEN(TCPH, I6, segmentSizes1, segmentsNum1)> Ipv6TcpHpcRndisTest {"Ipv6TcpHpcRndisTest", "IPv6 + TCP"};

+ 176 - 0
kernel-tests/UlsoTestFixture.h

@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+#ifndef ULSOTESTFIXTURE_H_
+#define ULSOTESTFIXTURE_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 "network_traffic/UlsoPacket.h"
+
+using std::cout;
+using std::endl;
+using std::string;
+
+class UlsoTestFixture: public TestBase {
+
+public:
+
+	UlsoTestFixture(){
+		m_testSuiteName.push_back("ULSO");
+		memset(m_sendBuf, 0, sizeof(m_sendBuf));
+		memset(m_receiveBuf, 0, sizeof(m_receiveBuf));
+		memset(m_segmentBuf, 0, sizeof(m_segmentBuf));
+	}
+
+	virtual bool Setup() {
+		if(!setupKernelModule()){
+			return false;
+		}
+		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);
+		return true;
+	}
+
+	virtual bool Teardown(){
+		m_producer.Close();
+		m_consumer.Close();
+		return true;
+	}
+
+	virtual bool Run() = 0;
+
+protected:
+
+	virtual void configFromEp(struct test_ipa_ep_cfg *ep_cfg){
+		return;
+	}
+
+	size_t clearPipe(){
+		cout << "In clearPipe" << endl;
+		if(m_consumer.setReadNoBlock() == -1){
+			cout << "Error: setReadNoBlock returned -1" << endl;
+			return 0;
+		}
+		size_t recievedBytes = m_consumer.ReceiveSingleDataChunk(m_receiveBuf, UlsoPacket<>::maxSize);
+		size_t totalReceivedBytes = recievedBytes;
+		if(recievedBytes > 0){
+			unsigned count = 1;
+			while(recievedBytes){
+				cout << "Receive #" << count << endl;
+				printBuf(m_receiveBuf, recievedBytes, string("Rceived ")
+					+ std::to_string(recievedBytes) + string(" Bytes:"));
+				recievedBytes = m_consumer.ReceiveSingleDataChunk(m_receiveBuf, UlsoPacket<>::maxSize);
+				totalReceivedBytes += recievedBytes;
+				count ++;
+			}
+		} else {
+			cout << "There were no bytes left in the pipe" << endl;
+		}
+		m_consumer.clearReadNoBlock();
+		return totalReceivedBytes;
+	}
+
+	bool fail(size_t sendSize=0, size_t totalSegmentsSize=0, size_t recievedBytes=0){
+		printBuf(m_sendBuf, sendSize, "Sent:");
+		printBuf(m_receiveBuf, recievedBytes, string("Rceived ") + std::to_string(recievedBytes) + string(" Bytes:"));
+		printBuf(m_segmentBuf, totalSegmentsSize, string("Expected to receive ") + std::to_string(totalSegmentsSize) + string(" Bytes:"));
+		clearPipe();
+		return false;
+	}
+
+	virtual int setupKernelModule(bool en_status = 0){
+		struct ipa_channel_config from_ipa_channels[1];
+		struct test_ipa_ep_cfg from_ipa_cfg[1];
+		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[1];
+
+		/* From ipa configurations - 1 pipe */
+		memset(&from_ipa_cfg[0], 0, sizeof(from_ipa_cfg[0]));
+		from_ipa_cfg[0].ulso.is_ulso_pipe = true;
+		configFromEp(&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]),
+				en_status);
+		from_ipa_array[0] = &from_ipa_channels[0];
+
+		/* To ipa configurations - 1 pipe */
+		memset(&to_ipa_cfg[0], 0, sizeof(to_ipa_cfg[0]));
+		to_ipa_cfg[0].ulso.ipid_min_max_idx = 0;
+		to_ipa_cfg[0].ulso.is_ulso_pipe = true;
+		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);
+
+		return GenericConfigureScenario(&header, true);
+	}
+
+protected:
+
+	static void printBuf(uint8_t* buf, size_t bufSize, string title=""){
+		if(bufSize == 0){
+			return;
+		}
+		cout << title << endl << std::hex;
+		for (size_t i = 0; i < bufSize-1; i++)
+			cout << std::setfill('0') << std::setw(2) << static_cast<int>(buf[i]) << " ";
+		cout << std::setfill('0') << std::setw(2) << static_cast<int>(buf[bufSize-1]) << std::dec << endl;
+	}
+
+public:
+
+	InterfaceAbstraction m_producer;
+	InterfaceAbstraction m_consumer;
+	uint8_t m_sendBuf[UlsoPacket<>::maxSize];
+	uint8_t m_receiveBuf[UlsoPacket<>::maxSize];
+	uint8_t m_segmentBuf[UlsoPacket<>::maxSize];
+};
+#endif /* ULSOTESTFIXTURE_H_ */

+ 1 - 1
kernel-tests/main.cpp

@@ -49,7 +49,7 @@ string sFormat = "ip_accelerator <control_flag> <suit/name>, ..., <suit/name>\n"
 							"ip_accelerator " SHOW_SUIT_FLAG  "\n"
 							"or ip_accelerator --chooser "
 							"for menu chooser interface\n";
-#define MAX_SUITES 15
+#define MAX_SUITES 17
 
 #undef strcasesame
 #define strcasesame(x, y) \

+ 1 - 1
kernel-tests/network_traffic/UlsoPacket.h

@@ -88,7 +88,7 @@ public:
     Transport mTransportHeader;
     vector<uint8_t> mPayload {};
 
-    UlsoPacket(unsigned int segmentSize, unsigned int payloadSize, bool ethernetHeaderValid=false):
+    UlsoPacket(unsigned int segmentSize, unsigned int payloadSize, bool ethernetHeaderValid=true):
         mEthernetHeaderValid(ethernetHeaderValid){
         bool first = true;
         uint32_t seqNum = 0;