Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8aded3de authored by Michael Adisumarta's avatar Michael Adisumarta
Browse files

msm: ipa: Add IPv6 NAT uc activation interface



Add IOCTLs for adding and deleting uc activation entries.
Amend Socksv5 add\delete entry algorithm to allow IPv6 NAT
and Socksv5 entries to co-exist in activation table.
Add debugfs entry to dump uc activation table.

Change-Id: I5382a393cb2890cd6c6ee4dc73eadf16c603294a
Signed-off-by: default avatarAmir Levy <alevy@codeaurora.org>
Signed-off-by: default avatarMichael Adisumarta <madisuma@codeaurora.org>
parent f3883bd3
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -1003,6 +1003,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
	struct ipa_ioc_get_vlan_mode vlan_mode;
	struct ipa_ioc_wigig_fst_switch fst_switch;
	struct ipa_nat_in_sram_info nat_in_sram_info;
	union ipa_ioc_uc_activation_entry uc_act;
	size_t sz;
	int pre_entry;
	int hdl;
@@ -3052,6 +3053,39 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
		}
		break;

	case IPA_IOC_ADD_UC_ACT_ENTRY:
		if (copy_from_user(&uc_act, (const void __user *)arg,
			sizeof(union ipa_ioc_uc_activation_entry))) {
			IPAERR_RL("copy_from_user fails\n");
			retval = -EFAULT;
			break;
		}

		/* first field in both structs is cmd id */
		if (uc_act.socks.cmd_id == IPA_SOCKSV5_ADD_COM_ID) {
			retval = ipa3_add_socksv5_conn_usr(&uc_act.socks);
		} else {
			retval = ipa3_add_ipv6_nat_uc_activation_entry(
				&uc_act.ipv6_nat);
		}
		if (retval) {
			retval = -EFAULT;
			break;
		}
		if (copy_to_user((void __user *)arg, &uc_act,
			sizeof(union ipa_ioc_uc_activation_entry))) {
			IPAERR_RL("copy_to_user fails\n");
			retval = -EFAULT;
			break;
		}
		break;
	case IPA_IOC_DEL_UC_ACT_ENTRY:
		if (ipa3_del_uc_act_entry((uint16_t)arg)) {
			retval = -EFAULT;
			break;
		}
		break;

	default:
		IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
		return -ENOTTY;
+127 −4
Original line number Diff line number Diff line
@@ -2646,6 +2646,125 @@ static ssize_t ipa3_enable_ipc_low(struct file *file,
	return count;
}

static ssize_t ipa3_read_uc_act_tbl(struct file *file,
	char __user *ubuf, size_t count, loff_t *ppos)
{
	int nbytes;
	int cnt = 0;
	int i;
	struct ipa_ipv6_nat_uc_tmpl *uc_entry_nat;
	struct ipa_socksv5_uc_tmpl *uc_entry_socks;
	struct iphdr_rsv *socks_iphdr;
	struct ipv6hdr *socks_ipv6hdr;

	/* IPA version check */
	if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) {
		nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
			"This feature only support on IPA4.5+\n");
		cnt += nbytes;
		goto done;
	}

	if (!ipa3_ctx->uc_act_tbl_valid) {
		IPAERR("uC act tbl wasn't allocated\n");
		return -ENOENT;
	}

	if (sizeof(dbg_buff) < count + 1)
		return -EFAULT;

	dbg_buff[count] = '\0';

	mutex_lock(&ipa3_ctx->act_tbl_lock);

	uc_entry_nat = (struct ipa_ipv6_nat_uc_tmpl *)
		(ipa3_ctx->uc_act_tbl.base);
	nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
		"uc_act_tbl_total %d, uc_act_tbl_ipv6_nat_total %d uc_act_tbl_socksv5_total %d, uc_act_tbl_next_index %d\n"
		"uC activation entries:"
		, ipa3_ctx->uc_act_tbl_total,
		ipa3_ctx->uc_act_tbl_ipv6_nat_total,
		ipa3_ctx->uc_act_tbl_socksv5_total,
		ipa3_ctx->uc_act_tbl_next_index);
	cnt += nbytes;
	for (i = 0; i < IPA_UC_ACT_TBL_SIZE; i++) {
		if (uc_entry_nat[i].cmd_id == IPA_IPv6_NAT_COM_ID) {
			nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
				"\nentry %d:\n"
				"cmd_id = IPV6_NAT\n"
				"private_address_msb 0x%llX\n"
				"private_address_lsb 0x%llX\n"
				"private_port %u\n"
				"public_address_msb 0x%llX\n"
				"public_address_lsb 0x%llX\n"
				"public_port %u\n",
				i,
				uc_entry_nat[i].private_address_msb,
				uc_entry_nat[i].private_address_lsb,
				uc_entry_nat[i].private_port,
				uc_entry_nat[i].public_address_msb,
				uc_entry_nat[i].public_address_lsb,
				uc_entry_nat[i].public_port);
			cnt += nbytes;
		} else if (uc_entry_nat[i].cmd_id == IPA_SOCKSV5_ADD_COM_ID) {
			uc_entry_socks = (struct ipa_socksv5_uc_tmpl *)
				(uc_entry_nat);
			nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
				"\nentry %d:\n"
				"cmd_id = SOCKSv5\n"
				"cmd_param: %u\n"
				"source_port: %u\n"
				"dest_port: %u\n"
				"ipa_socksv5_mask: %x\n",
				i,
				uc_entry_socks[i].cmd_param,
				uc_entry_socks[i].src_port,
				uc_entry_socks[i].dst_port,
				uc_entry_socks[i].ipa_sockv5_mask);
			cnt += nbytes;

			if (uc_entry_socks[i].cmd_param ==
					IPA_SOCKsv5_ADD_V6_V4_COM_PM) {
				socks_iphdr =
					&uc_entry_socks[i].ip_hdr.ipv4_rsv;
				nbytes = scnprintf(dbg_buff + cnt,
					IPA_MAX_MSG_LEN,
					"ipv4_src_addr: 0x%X\n"
					"ipv4_dst_addr: 0x%X\n",
					socks_iphdr->ipv4_temp.saddr,
					socks_iphdr->ipv4_temp.daddr);
				cnt += nbytes;
			} else {
				socks_ipv6hdr =
					&uc_entry_socks[i].ip_hdr.ipv6_temp;
				nbytes = scnprintf(dbg_buff + cnt,
					IPA_MAX_MSG_LEN,
					"ipv6_src_addr[0]: 0x%X\n"
					"ipv6_src_addr[1]: 0x%X\n"
					"ipv6_src_addr[2]: 0x%X\n"
					"ipv6_src_addr[3]: 0x%X\n"
					"ipv6_dts_addr[0]: 0x%X\n"
					"ipv6_dts_addr[1]: 0x%X\n"
					"ipv6_dts_addr[2]: 0x%X\n"
					"ipv6_dts_addr[3]: 0x%X\n",
					socks_ipv6hdr->saddr.s6_addr32[0],
					socks_ipv6hdr->saddr.s6_addr32[1],
					socks_ipv6hdr->saddr.s6_addr32[2],
					socks_ipv6hdr->saddr.s6_addr32[3],
					socks_ipv6hdr->daddr.s6_addr32[0],
					socks_ipv6hdr->daddr.s6_addr32[1],
					socks_ipv6hdr->daddr.s6_addr32[2],
					socks_ipv6hdr->daddr.s6_addr32[3]);
				cnt += nbytes;
			}
		}
	}
	mutex_unlock(&ipa3_ctx->act_tbl_lock);
done:
	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);

}

static const struct ipa3_debugfs_file debugfs_files[] = {
	{
		"gen_reg", IPA_READ_ONLY_MODE, NULL, {
@@ -2811,7 +2930,11 @@ static const struct ipa3_debugfs_file debugfs_files[] = {
		"app_clk_vote_cnt", IPA_READ_ONLY_MODE, NULL, {
			.read = ipa3_read_app_clk_vote,
		}
	},
	}, {
		"uc_act_table", IPA_READ_ONLY_MODE, NULL, {
			.read = ipa3_read_uc_act_tbl,
		}
	}
};

void ipa3_debugfs_pre_init(void)
+11 −0
Original line number Diff line number Diff line
@@ -2022,6 +2022,8 @@ struct ipa3_context {
	bool uc_act_tbl_valid;
	struct mutex act_tbl_lock;
	int uc_act_tbl_total;
	int uc_act_tbl_socksv5_total;
	int uc_act_tbl_ipv6_nat_total;
	int uc_act_tbl_next_index;
	bool manual_fw_load;
};
@@ -2419,6 +2421,15 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info);

int ipa3_del_socksv5_conn(uint32_t handle);

int ipa3_add_socksv5_conn_usr(struct ipa_kernel_tests_socksv5_uc_tmpl *tmpl);

int ipa3_add_ipv6_nat_uc_activation_entry(
	struct ipa_ioc_ipv6_nat_uc_act_entry *entry);

int ipa3_del_ipv6_nat_uc_activation_entry(uint16_t index);

int ipa3_del_uc_act_entry(uint16_t index);

/*
 * Header removal / addition
 */
+409 −53
Original line number Diff line number Diff line
@@ -9150,6 +9150,213 @@ int ipa3_setup_uc_act_tbl(void)
	return res;
}

static inline bool is_free_socksv5(struct ipa_socksv5_uc_tmpl *socksv5_entry)
{
	if ((!socksv5_entry->cmd_id) ||
		(socksv5_entry->cmd_id == IPA_SOCKsv5_ADD_COM_ID &&
		!(socksv5_entry->ipa_sockv5_mask & IPA_SOCKSv5_ENTRY_VALID)))
		return true;
	return false;
}

static int ipa3_get_free_uc_act_entry(void)
{
	struct ipa_socksv5_uc_tmpl *entry;
	int orig_index = ipa3_ctx->uc_act_tbl_next_index;
	int free_index = -1;

	IPADBG("\n");
	/* find a free spot*/
	do {
		entry = ipa3_ctx->uc_act_tbl.base +
			ipa3_ctx->uc_act_tbl_next_index
			* sizeof(struct ipa_socksv5_uc_tmpl);

		/* check if entry is free */
		if (is_free_socksv5(entry)) {
			free_index = ipa3_ctx->uc_act_tbl_next_index;
			IPADBG("found free index at %d\n", free_index);
			break;
		}

		ipa3_ctx->uc_act_tbl_next_index++;
		ipa3_ctx->uc_act_tbl_next_index %=
			IPA_UC_ACT_TBL_SIZE;
	} while (orig_index != ipa3_ctx->uc_act_tbl_next_index);
	IPADBG("exit free_index %d\n", free_index);
	return free_index;
}

int ipa3_add_ipv6_nat_uc_activation_entry(
	struct ipa_ioc_ipv6_nat_uc_act_entry *entry)
{
	int res = 0;
	int index;
	struct ipa_ipv6_nat_uc_tmpl *uc_entry;

	/* IPA version check */
	if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) {
		IPAERR("Not support !\n");
		return -EPERM;
	}

	if (!ipa3_ctx->uc_act_tbl_valid) {
		IPAERR("uC act tbl wasn't allocated\n");
		return -ENOENT;
	}

	if (!entry) {
		IPAERR("Null entry\n");
		return -EIO;
	}
	if (!entry->private_address_lsb || !entry->private_address_msb
		|| !entry->public_address_lsb || !entry->public_address_msb
		|| !entry->private_port || !entry->public_port) {
		IPAERR("0 param 0x%llX 0x%llX 0x%llX 0x%llX %d %d\n",
			entry->private_address_lsb, entry->private_address_msb,
			entry->public_address_lsb, entry->public_address_msb,
			entry->private_port, entry->public_port);
		return -EFAULT;
	}

	mutex_lock(&ipa3_ctx->act_tbl_lock);
	/* check the left # of entries */
	if (ipa3_ctx->uc_act_tbl_total
		>= IPA_UC_ACT_TBL_SIZE) {
		IPAERR("uc act tbl is full!\n");
		res = -EFAULT;
		goto error;
	}

	index = ipa3_get_free_uc_act_entry();

	uc_entry = (struct ipa_ipv6_nat_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base +
		index * sizeof(struct ipa_ipv6_nat_uc_tmpl));

	uc_entry->private_address_lsb = entry->private_address_lsb;
	uc_entry->private_address_msb = entry->private_address_msb;
	uc_entry->public_address_lsb = entry->public_address_lsb;
	uc_entry->public_address_msb = entry->public_address_msb;
	uc_entry->private_port = entry->private_port;
	uc_entry->public_port = entry->public_port;
	uc_entry->cmd_id = IPA_IPv6_NAT_COM_ID;

	/* set output index */
	entry->index = (uint16_t)index;

	ipa3_ctx->uc_act_tbl_total++;
	ipa3_ctx->uc_act_tbl_ipv6_nat_total++;

	if (ipa3_ctx->uc_act_tbl_total < IPA_UC_ACT_TBL_SIZE) {
		/*
		 * find next free spot, this function shall update
		 * uc_act_tbl_next_index
		 */
		index = ipa3_get_free_uc_act_entry();

		if (index < 0) {
			/* set to max tbl size to debug */
			IPAERR("can't find available spot!\n");
			ipa3_ctx->uc_act_tbl_total = IPA_UC_ACT_TBL_SIZE;
			res = -EFAULT;
		}
	}
error:
	mutex_unlock(&ipa3_ctx->act_tbl_lock);
	return res;
}

int ipa3_del_uc_act_entry(uint16_t index)
{
	struct ipa_ipv6_nat_uc_tmpl *uc_entry;
	uint16_t cmd_id;

	/* IPA version check */
	if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) {
		IPAERR_RL("Not support !\n");
		return -EPERM;
	}

	if (!ipa3_ctx->uc_act_tbl_valid) {
		IPAERR_RL("uC act tbl haven't allocated\n");
		return -ENOENT;
	}

	if (index > IPA_UC_ACT_TBL_SIZE || index < 0) {
		IPAERR_RL("invalid index!\n");
		return -EINVAL;
	}

	if (!ipa3_ctx->uc_act_tbl_total) {
		IPAERR_RL(
			"invalid handle, no uc activation entries in table (total %d)\n"
			, ipa3_ctx->uc_act_tbl_total);
		return -EINVAL;
	}

	uc_entry = (struct ipa_ipv6_nat_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base +
		index * sizeof(struct ipa_ipv6_nat_uc_tmpl));

	mutex_lock(&ipa3_ctx->act_tbl_lock);
	cmd_id = uc_entry->cmd_id;
	mutex_unlock(&ipa3_ctx->act_tbl_lock);

	if (cmd_id == IPA_IPv6_NAT_COM_ID)
		return ipa3_del_ipv6_nat_uc_activation_entry(index);
	else
		return ipa3_del_socksv5_conn(index);
}

int ipa3_del_ipv6_nat_uc_activation_entry(uint16_t index)
{
	struct ipa_ipv6_nat_uc_tmpl *uc_entry;
	int res = 0;

	/* IPA version check */
	if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) {
		IPAERR_RL("Not support !\n");
		return -EPERM;
	}

	if (!ipa3_ctx->uc_act_tbl_valid) {
		IPAERR_RL("uC act tbl haven't allocated\n");
		return -ENOENT;
	}

	if (index > IPA_UC_ACT_TBL_SIZE || index < 0) {
		IPAERR_RL("invalid index!\n");
		return -EINVAL;
	}

	if (!ipa3_ctx->uc_act_tbl_ipv6_nat_total) {
		IPAERR_RL(
			"invalid handle, no IPv6 NAT entries in table (total %d)\n"
		, ipa3_ctx->uc_act_tbl_total);
		return -EINVAL;
	}

	uc_entry = (struct ipa_ipv6_nat_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base +
		index * sizeof(struct ipa_ipv6_nat_uc_tmpl));

	mutex_lock(&ipa3_ctx->act_tbl_lock);
	if (uc_entry->cmd_id != IPA_IPv6_NAT_COM_ID) {
		IPAERR_RL("entry %d wrong cmd id %d\n", uc_entry->cmd_id);
		res = -EFAULT;
		goto error;
	}
	uc_entry->cmd_id = 0;
	ipa3_ctx->uc_act_tbl_total--;
	ipa3_ctx->uc_act_tbl_ipv6_nat_total--;

	IPADBG("free entry %d, nat total %d, left total %d\n",
		index,
		ipa3_ctx->uc_act_tbl_ipv6_nat_total,
		ipa3_ctx->uc_act_tbl_total);
error:
	mutex_unlock(&ipa3_ctx->act_tbl_lock);
	return res;
}

static void ipa3_socksv5_msg_free_cb(void *buff, u32 len, u32 type)
{
	if (!buff) {
@@ -9167,6 +9374,39 @@ static void ipa3_socksv5_msg_free_cb(void *buff, u32 len, u32 type)
	kfree(buff);
}

static int ipa3_get_free_socksv5_entry(void)
{
	struct ipa_socksv5_uc_tmpl *first;
	struct ipa_socksv5_uc_tmpl *next;
	int orig_index = ipa3_ctx->uc_act_tbl_next_index;
	int free_index = -1;

	IPADBG("\n");
	/* find a free spot with two contiguous entries*/
	do {
		first = ipa3_ctx->uc_act_tbl.base +
			ipa3_ctx->uc_act_tbl_next_index
			* sizeof(struct ipa_socksv5_uc_tmpl);
		next = ipa3_ctx->uc_act_tbl.base +
			(ipa3_ctx->uc_act_tbl_next_index + 1)
			* sizeof(struct ipa_socksv5_uc_tmpl);

		/* check if first entry and next entry are free */
		if (is_free_socksv5(first) && is_free_socksv5(next)) {
			free_index = ipa3_ctx->uc_act_tbl_next_index;
			IPADBG("found free index at %d\n", free_index);
			break;
		}

		ipa3_ctx->uc_act_tbl_next_index += 2;
		ipa3_ctx->uc_act_tbl_next_index %=
			IPA_UC_ACT_TBL_SIZE;
	} while (orig_index != ipa3_ctx->uc_act_tbl_next_index);

	IPADBG("exit free_index %d\n", free_index);
	return free_index;
}

/**
 * ipa3_add_socksv5_conn() - IPA add socksv5_conn
 *
@@ -9176,8 +9416,8 @@ static void ipa3_socksv5_msg_free_cb(void *buff, u32 len, u32 type)
 */
int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info)
{
	int res = 0;
	void *rp_va, *wp_va;
	int res = 0, index;
	void *wp_va;
	struct ipa_socksv5_msg *socksv5_msg;
	struct ipa_msg_meta msg_meta;

@@ -9198,18 +9438,24 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info)
	}

	mutex_lock(&ipa3_ctx->act_tbl_lock);
	/* check the left # of entries */
	/* check the left # of entries (need at least 2)*/
	if (ipa3_ctx->uc_act_tbl_total
		>= IPA_UC_ACT_TBL_SIZE)	{
		>= IPA_UC_ACT_TBL_SIZE - 1)	{
		IPAERR("uc act tbl is full!\n");
		res = -EFAULT;
		goto error;
	}

	index = ipa3_get_free_socksv5_entry();
	if (index < 0) {
		IPAERR("couldn't find free socksv5 entry\n");
		res = -EFAULT;
		goto error;
	}

	/* Copied the act-info to tbl */
	wp_va = ipa3_ctx->uc_act_tbl.base +
		ipa3_ctx->uc_act_tbl_next_index
			* sizeof(struct ipa_socksv5_uc_tmpl);
		index * sizeof(struct ipa_socksv5_uc_tmpl);

	/* check entry valid */
	if ((info->ul_out.cmd_id != IPA_SOCKsv5_ADD_COM_ID)
@@ -9246,9 +9492,10 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info)
		&(info->dl_out), sizeof(info->dl_out));

	/* set output handle */
	info->handle = (uint16_t) ipa3_ctx->uc_act_tbl_next_index;
	info->handle = (uint16_t) index;

	ipa3_ctx->uc_act_tbl_total += 2;
	ipa3_ctx->uc_act_tbl_socksv5_total += 2;

	/* send msg to ipacm */
	socksv5_msg = kzalloc(sizeof(*socksv5_msg), GFP_KERNEL);
@@ -9261,9 +9508,9 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info)
	memcpy(&(socksv5_msg->dl_in), &(info->dl_in), sizeof(info->dl_in));
	socksv5_msg->handle = info->handle;
	socksv5_msg->ul_in.index =
		(uint16_t) ipa3_ctx->uc_act_tbl_next_index;
		(uint16_t) index;
	socksv5_msg->dl_in.index =
		(uint16_t) ipa3_ctx->uc_act_tbl_next_index + 1;
		(uint16_t) index + 1;

	memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
	msg_meta.msg_type = IPA_SOCKV5_ADD;
@@ -9276,27 +9523,14 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info)
		goto error;
	}

	if (ipa3_ctx->uc_act_tbl_total < IPA_UC_ACT_TBL_SIZE) {
		/* find next free spot */
		do {
			ipa3_ctx->uc_act_tbl_next_index += 2;
			ipa3_ctx->uc_act_tbl_next_index %=
				IPA_UC_ACT_TBL_SIZE;

			rp_va =  ipa3_ctx->uc_act_tbl.base +
				ipa3_ctx->uc_act_tbl_next_index
					* sizeof(struct ipa_socksv5_uc_tmpl);

			if (!((((struct ipa_socksv5_uc_tmpl *) rp_va)->
				ipa_sockv5_mask) & IPA_SOCKSv5_ENTRY_VALID)) {
				IPADBG("next available entry %d, total %d\n",
				ipa3_ctx->uc_act_tbl_next_index,
				ipa3_ctx->uc_act_tbl_total);
				break;
			}
		} while (rp_va != wp_va);
	if (ipa3_ctx->uc_act_tbl_total < IPA_UC_ACT_TBL_SIZE - 1) {
		/*
		 * find next free spot, this function shall update
		 * uc_act_tbl_next_index
		 */
		index = ipa3_get_free_socksv5_entry();

		if (rp_va == wp_va) {
		if (index < 0) {
			/* set to max tbl size to debug */
			IPAERR("can't find available spot!\n");
			ipa3_ctx->uc_act_tbl_total = IPA_UC_ACT_TBL_SIZE;
@@ -9308,6 +9542,127 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info)
	mutex_unlock(&ipa3_ctx->act_tbl_lock);
	return res;
}
/*
 * ipa3_add_socksv5_conn_usr() - IPA copy and add socksv5 conn
 *
 * Returns: 0 on success, negative on failure
 *
 * Note : Should not be called from atomic context
 */
int ipa3_add_socksv5_conn_usr(struct ipa_kernel_tests_socksv5_uc_tmpl *tmpl)
{
	struct ipa_socksv5_info info;
	int retval = 0;

	memset(&info, 0, sizeof(struct ipa_socksv5_info));

	if (tmpl->direction == 0) { /* DL */
		info.dl_out.cmd_id = tmpl->cmd_id;
		info.dl_out.cmd_param = tmpl->cmd_param;
		info.dl_out.ip_hdr.ipv6_temp.version = 6;
		info.dl_out.ip_hdr.ipv6_temp.nexthdr = 6;
		info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[0] =
			tmpl->ipv6_src_addr[0];
		info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[1] =
			tmpl->ipv6_src_addr[1];
		info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[2] =
			tmpl->ipv6_src_addr[2];
		info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[3] =
			tmpl->ipv6_src_addr[3];
		info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[0] =
			tmpl->ipv6_dst_addr[0];
		info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[1] =
			tmpl->ipv6_dst_addr[1];
		info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[2] =
			tmpl->ipv6_dst_addr[2];
		info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[3] =
			tmpl->ipv6_dst_addr[3];
		info.dl_out.src_port = tmpl->src_port;
		info.dl_out.dst_port = tmpl->dst_port;
		info.dl_out.ipa_sockv5_mask = tmpl->ipa_sockv5_mask;
		info.dl_out.out_irs = tmpl->out_irs;
		info.dl_out.out_iss = tmpl->out_iss;
		info.dl_out.in_irs = tmpl->in_irs;
		info.dl_out.in_iss = tmpl->in_iss;
		info.dl_out.out_ircv_tsval = tmpl->out_ircv_tsval;
		info.dl_out.in_ircv_tsecr = tmpl->in_ircv_tsecr;
		info.dl_out.out_ircv_tsecr = tmpl->out_ircv_tsecr;
		info.dl_out.in_ircv_tsval = tmpl->in_ircv_tsval;
		info.dl_out.in_isnd_wscale = tmpl->in_isnd_wscale;
		info.dl_out.out_isnd_wscale = tmpl->out_isnd_wscale;
		info.dl_out.in_ircv_wscale = tmpl->in_ircv_wscale;
		info.dl_out.out_ircv_wscale = tmpl->out_ircv_wscale;

		/* for UL set default values to pass pair validity check */
		info.ul_out.cmd_id = IPA_SOCKsv5_ADD_COM_ID;
		info.ul_out.cmd_param = IPA_SOCKsv5_ADD_V6_V4_COM_PM;
	} else if (tmpl->direction == 1) { /* UL */
		info.ul_out.cmd_id = tmpl->cmd_id;
		info.ul_out.cmd_param = tmpl->cmd_param;
		if (info.ul_out.cmd_param == IPA_SOCKsv5_ADD_V6_V4_COM_PM) {
			info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.version = 4;
			info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.ihl = 5;
			info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.saddr =
				tmpl->ip_src_addr;
			info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.daddr =
				tmpl->ip_dst_addr;
			info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.protocol = 6;
		}
		if (info.ul_out.cmd_param == IPA_SOCKsv5_ADD_V6_V6_COM_PM) {
			info.ul_out.ip_hdr.ipv6_temp.version = 6;
			info.ul_out.ip_hdr.ipv6_temp.nexthdr = 6;
			info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[0] =
				tmpl->ipv6_src_addr[0];
			info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[1] =
				tmpl->ipv6_src_addr[1];
			info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[2] =
				tmpl->ipv6_src_addr[2];
			info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[3] =
				tmpl->ipv6_src_addr[3];
			info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[0] =
				tmpl->ipv6_dst_addr[0];
			info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[1] =
				tmpl->ipv6_dst_addr[1];
			info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[2] =
				tmpl->ipv6_dst_addr[2];
			info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[3] =
				tmpl->ipv6_dst_addr[3];
		}
		info.ul_out.src_port = tmpl->src_port;
		info.ul_out.dst_port = tmpl->dst_port;
		info.ul_out.ipa_sockv5_mask = tmpl->ipa_sockv5_mask;
		info.ul_out.out_irs = tmpl->out_irs;
		info.ul_out.out_iss = tmpl->out_iss;
		info.ul_out.in_irs = tmpl->in_irs;
		info.ul_out.in_iss = tmpl->in_iss;
		info.ul_out.out_ircv_tsval = tmpl->out_ircv_tsval;
		info.ul_out.in_ircv_tsecr = tmpl->in_ircv_tsecr;
		info.ul_out.out_ircv_tsecr = tmpl->out_ircv_tsecr;
		info.ul_out.in_ircv_tsval = tmpl->in_ircv_tsval;
		info.ul_out.in_isnd_wscale = tmpl->in_isnd_wscale;
		info.ul_out.out_isnd_wscale = tmpl->out_isnd_wscale;
		info.ul_out.in_ircv_wscale = tmpl->in_ircv_wscale;
		info.ul_out.out_ircv_wscale = tmpl->out_ircv_wscale;

		/* for DL set default values to pass pair validity check */
		info.dl_out.cmd_param = IPA_SOCKsv5_ADD_V4_V6_COM_PM;
		info.dl_out.cmd_id = IPA_SOCKsv5_ADD_COM_ID;
	} else {
		IPAERR("invalid socksv5 direction: %d\n", tmpl->direction);
		return -EINVAL;
	}

	retval = ipa3_add_socksv5_conn(&info);
	if (retval) {
		IPAERR("ipa3_add_socksv5_conn failed retval: %d\n", retval);
		return retval;
	}

	/* save uc handle */
	tmpl->handle = info.handle;

	return retval;
}

/**
 * ipa3_del_socksv5_conn() - IPA add socksv5_conn
@@ -9319,9 +9674,9 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info)
int ipa3_del_socksv5_conn(uint32_t handle)
{
	int res = 0;
	void *rp_va;
	uint32_t *socksv5_handle;
	struct ipa_msg_meta msg_meta;
	struct ipa_socksv5_uc_tmpl *entry, *next;

	/* IPA version check */
	if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) {
@@ -9339,43 +9694,44 @@ int ipa3_del_socksv5_conn(uint32_t handle)
		return -EINVAL;
	}

	if ((handle % 2) != 0) {
		IPAERR("invalid handle!\n");
	if (ipa3_ctx->uc_act_tbl_socksv5_total < 2) {
		IPAERR("invalid handle, tbl doesn't have socksv5 entries!\n");
		return -EINVAL;
	}

	if (ipa3_ctx->uc_act_tbl_total < 2) {
		IPAERR("invalid handle, all tbl is empty!\n");
		return -EINVAL;
	}

	rp_va =  ipa3_ctx->uc_act_tbl.base +
			handle * sizeof(struct ipa_socksv5_uc_tmpl);
	entry = (struct ipa_socksv5_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base +
			handle * sizeof(struct ipa_socksv5_uc_tmpl));
	next = (struct ipa_socksv5_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base +
		(handle + 1) * sizeof(struct ipa_socksv5_uc_tmpl));

	/* check entry is valid or not */
	mutex_lock(&ipa3_ctx->act_tbl_lock);
	if (!((((struct ipa_socksv5_uc_tmpl *) rp_va)->
		ipa_sockv5_mask) & IPA_SOCKSv5_ENTRY_VALID)) {
		IPADBG(" entry %d already free\n", handle);
	if (entry->cmd_id != IPA_SOCKsv5_ADD_COM_ID) {
		IPAERR(" entry %d not socksv5\n", handle);
		res = -EINVAL;
		goto error;
	}
	if (next->cmd_id != IPA_SOCKsv5_ADD_COM_ID) {
		IPAERR(" entry %d not socksv5\n", handle + 1);
		res = -EINVAL;
		goto error;
	}
	if (!(entry->ipa_sockv5_mask & IPA_SOCKSv5_ENTRY_VALID))
		IPADBG(" entry %d already free\n", handle);

	if (!((((struct ipa_socksv5_uc_tmpl *) (rp_va +
		sizeof(struct ipa_socksv5_uc_tmpl)))->
		ipa_sockv5_mask) & IPA_SOCKSv5_ENTRY_VALID)) {
	if (!(next->ipa_sockv5_mask & IPA_SOCKSv5_ENTRY_VALID))
		IPADBG(" entry %d already free\n", handle);
	}

	((struct ipa_socksv5_uc_tmpl *) rp_va)->ipa_sockv5_mask
		&= ~IPA_SOCKSv5_ENTRY_VALID;
	((struct ipa_socksv5_uc_tmpl *) (rp_va +
		sizeof(struct ipa_socksv5_uc_tmpl)))->ipa_sockv5_mask
			&= ~IPA_SOCKSv5_ENTRY_VALID;
	entry->ipa_sockv5_mask &= ~IPA_SOCKSv5_ENTRY_VALID;
	next->ipa_sockv5_mask &= ~IPA_SOCKSv5_ENTRY_VALID;
	ipa3_ctx->uc_act_tbl_total -= 2;
	ipa3_ctx->uc_act_tbl_socksv5_total -= 2;

	IPADBG("free entry %d and %d, left total %d\n",
	IPADBG("free entry %d and %d, left total %d, socksv5 total %d\n",
		handle,
		handle + 1,
		ipa3_ctx->uc_act_tbl_total);
		ipa3_ctx->uc_act_tbl_total,
		ipa3_ctx->uc_act_tbl_socksv5_total);

	/* send msg to ipacm */
	socksv5_handle = kzalloc(sizeof(*socksv5_handle), GFP_KERNEL);
+27 −1
Original line number Diff line number Diff line
@@ -1423,9 +1423,35 @@ struct ipa_socksv5_info {
	struct ipacm_socksv5_info dl_in;

	/* output: handle (index) */
	uint32_t handle;
	uint16_t handle;
};

struct ipa_ipv6_nat_uc_tmpl {
	uint16_t cmd_id;
	uint16_t rsv;
	uint32_t cmd_param;
	uint16_t pkt_count;
	uint16_t rsv2;
	uint32_t byte_count;
	uint64_t private_address_lsb;
	uint64_t private_address_msb;
	uint64_t public_address_lsb;
	uint64_t public_address_msb;
	uint16_t private_port;
	uint16_t public_port;
	uint32_t rsv3;
	uint64_t rsv4;
	uint64_t rsv5;
	uint64_t rsv6;
	uint64_t rsv7;
	uint64_t rsv8;
	uint64_t rsv9;
	uint64_t rsv10;
	uint64_t rsv11;
	uint64_t rsv12;
} __packed;



#if defined CONFIG_IPA || defined CONFIG_IPA3

Loading