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

Commit 02c8579d authored by Amir Levy's avatar Amir Levy
Browse files

msm: ipa3: New IOCTL for adding rt\flt rule after a specific rule



Added IOCTL for adding a rule on a specific location on the
rt\flt table. The rule will be added after the rule with the
given handle.

Change-Id: I148561fecc7a2e2c9861dbce8975b02947839968
Signed-off-by: default avatarAmir Levy <alevy@codeaurora.org>
Signed-off-by: default avatarNadine Toledano <nadinet@codeaurora.org>
parent 1323f7a3
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
@@ -498,6 +498,37 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
			break;
		}
		break;
	case IPA_IOC_ADD_RT_RULE_AFTER:
		if (copy_from_user(header, (u8 *)arg,
			sizeof(struct ipa_ioc_add_rt_rule_after))) {

			retval = -EFAULT;
			break;
		}
		pyld_sz =
		   sizeof(struct ipa_ioc_add_rt_rule_after) +
		   ((struct ipa_ioc_add_rt_rule_after *)header)->num_rules *
		   sizeof(struct ipa_rt_rule_add);
		param = kzalloc(pyld_sz, GFP_KERNEL);
		if (!param) {
			retval = -ENOMEM;
			break;
		}
		if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
			retval = -EFAULT;
			break;
		}
		if (ipa3_add_rt_rule_after(
			(struct ipa_ioc_add_rt_rule_after *)param)) {

			retval = -EFAULT;
			break;
		}
		if (copy_to_user((u8 *)arg, param, pyld_sz)) {
			retval = -EFAULT;
			break;
		}
		break;

	case IPA_IOC_MDFY_RT_RULE:
		if (copy_from_user(header, (u8 *)arg,
@@ -586,6 +617,37 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
		}
		break;

	case IPA_IOC_ADD_FLT_RULE_AFTER:
		if (copy_from_user(header, (u8 *)arg,
				sizeof(struct ipa_ioc_add_flt_rule_after))) {

			retval = -EFAULT;
			break;
		}
		pyld_sz =
		   sizeof(struct ipa_ioc_add_flt_rule_after) +
		   ((struct ipa_ioc_add_flt_rule_after *)header)->num_rules *
		   sizeof(struct ipa_flt_rule_add);
		param = kzalloc(pyld_sz, GFP_KERNEL);
		if (!param) {
			retval = -ENOMEM;
			break;
		}
		if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
			retval = -EFAULT;
			break;
		}
		if (ipa3_add_flt_rule_after(
				(struct ipa_ioc_add_flt_rule_after *)param)) {
			retval = -EFAULT;
			break;
		}
		if (copy_to_user((u8 *)arg, param, pyld_sz)) {
			retval = -EFAULT;
			break;
		}
		break;

	case IPA_IOC_DEL_FLT_RULE:
		if (copy_from_user(header, (u8 *)arg,
					sizeof(struct ipa_ioc_del_flt_rule))) {
+219 −39
Original line number Diff line number Diff line
@@ -1038,14 +1038,9 @@ fail_gen:
	return rc;
}

static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip,
			      const struct ipa_flt_rule *rule, u8 add_rear,
			      u32 *rule_hdl)
static int __ipa_validate_flt_rule(const struct ipa_flt_rule *rule,
		struct ipa3_rt_tbl **rt_tbl, enum ipa_ip_type ip)
{
	struct ipa3_flt_entry *entry;
	struct ipa3_rt_tbl *rt_tbl = NULL;
	int id;

	if (rule->action != IPA_PASS_TO_EXCEPTION) {
		if (!rule->eq_attrib_type) {
			if (!rule->rt_tbl_hdl) {
@@ -1053,13 +1048,13 @@ static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip,
				goto error;
			}

			rt_tbl = ipa3_id_find(rule->rt_tbl_hdl);
			if (rt_tbl == NULL) {
			*rt_tbl = ipa3_id_find(rule->rt_tbl_hdl);
			if (*rt_tbl == NULL) {
				IPAERR("RT tbl not found\n");
				goto error;
			}

			if (rt_tbl->cookie != IPA_COOKIE) {
			if ((*rt_tbl)->cookie != IPA_COOKIE) {
				IPAERR("RT table cookie is invalid\n");
				goto error;
			}
@@ -1073,32 +1068,49 @@ static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip,
		}
	}

	entry = kmem_cache_zalloc(ipa3_ctx->flt_rule_cache, GFP_KERNEL);
	if (!entry) {
	return 0;

error:
	return -EPERM;
}

static int __ipa_create_flt_entry(struct ipa3_flt_entry **entry,
		const struct ipa_flt_rule *rule, struct ipa3_rt_tbl *rt_tbl,
		struct ipa3_flt_tbl *tbl)
{
	int id;

	*entry = kmem_cache_zalloc(ipa3_ctx->flt_rule_cache, GFP_KERNEL);
	if (!*entry) {
		IPAERR("failed to alloc FLT rule object\n");
		goto error;
	}
	INIT_LIST_HEAD(&entry->link);
	entry->rule = *rule;
	entry->cookie = IPA_COOKIE;
	entry->rt_tbl = rt_tbl;
	entry->tbl = tbl;
	INIT_LIST_HEAD(&((*entry)->link));
	(*entry)->rule = *rule;
	(*entry)->cookie = IPA_COOKIE;
	(*entry)->rt_tbl = rt_tbl;
	(*entry)->tbl = tbl;
	id = ipa3_alloc_rule_id(&tbl->rule_ids);
	if (id < 0) {
		IPAERR("failed to allocate rule id\n");
		WARN_ON(1);
		goto rule_id_fail;
	}
	entry->rule_id = id;
	if (add_rear) {
		if (tbl->sticky_rear)
			list_add_tail(&entry->link,
					tbl->head_flt_rule_list.prev);
		else
			list_add_tail(&entry->link, &tbl->head_flt_rule_list);
	} else {
		list_add(&entry->link, &tbl->head_flt_rule_list);
	(*entry)->rule_id = id;

	return 0;

rule_id_fail:
	kmem_cache_free(ipa3_ctx->flt_rule_cache, *entry);
error:
	return -EPERM;
}

static int __ipa_finish_flt_rule_add(struct ipa3_flt_tbl *tbl,
		struct ipa3_flt_entry *entry, u32 *rule_hdl)
{
	int id;

	tbl->rule_cnt++;
	if (entry->rt_tbl)
		entry->rt_tbl->ref_cnt++;
@@ -1111,14 +1123,80 @@ static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip,
	entry->id = id;
	IPADBG("add flt rule rule_cnt=%d\n", tbl->rule_cnt);

	return 0;
}

static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip,
			      const struct ipa_flt_rule *rule, u8 add_rear,
			      u32 *rule_hdl)
{
	struct ipa3_flt_entry *entry;
	struct ipa3_rt_tbl *rt_tbl = NULL;

	if (__ipa_validate_flt_rule(rule, &rt_tbl, ip))
		goto error;

	if (__ipa_create_flt_entry(&entry, rule, rt_tbl, tbl))
		goto error;

	if (add_rear) {
		if (tbl->sticky_rear)
			list_add_tail(&entry->link,
					tbl->head_flt_rule_list.prev);
		else
			list_add_tail(&entry->link, &tbl->head_flt_rule_list);
	} else {
		list_add(&entry->link, &tbl->head_flt_rule_list);
	}

	__ipa_finish_flt_rule_add(tbl, entry, rule_hdl);

	return 0;

rule_id_fail:
	kmem_cache_free(ipa3_ctx->flt_rule_cache, entry);
error:
	return -EPERM;
}

static int __ipa_add_flt_rule_after(struct ipa3_flt_tbl *tbl,
				const struct ipa_flt_rule *rule,
				u32 *rule_hdl,
				enum ipa_ip_type ip,
				struct ipa3_flt_entry **add_after_entry)
{
	struct ipa3_flt_entry *entry;
	struct ipa3_rt_tbl *rt_tbl = NULL;

	if (!*add_after_entry)
		goto error;

	if (rule == NULL || rule_hdl == NULL) {
		IPAERR("bad parms rule=%p rule_hdl=%p\n", rule,
				rule_hdl);
		goto error;
	}

	if (__ipa_validate_flt_rule(rule, &rt_tbl, ip))
		goto error;

	if (__ipa_create_flt_entry(&entry, rule, rt_tbl, tbl))
		goto error;

	list_add(&entry->link, &((*add_after_entry)->link));

	__ipa_finish_flt_rule_add(tbl, entry, rule_hdl);

	/*
	 * prepare for next insertion
	 */
	*add_after_entry = entry;

	return 0;

error:
	*add_after_entry = NULL;
	return -EPERM;
}

static int __ipa_del_flt_rule(u32 rule_hdl)
{
	struct ipa3_flt_entry *entry;
@@ -1212,6 +1290,24 @@ error:
	return -EPERM;
}

static int __ipa_add_flt_get_ep_idx(enum ipa_client_type ep, int *ipa_ep_idx)
{
	*ipa_ep_idx = ipa3_get_ep_mapping(ep);
	if (*ipa_ep_idx == IPA_FLT_TABLE_INDEX_NOT_FOUND) {
		IPAERR("ep not valid ep=%d\n", ep);
		return -EINVAL;
	}
	if (ipa3_ctx->ep[*ipa_ep_idx].valid == 0)
		IPADBG("ep not connected ep_idx=%d\n", *ipa_ep_idx);

	if (!ipa_is_ep_support_flt(*ipa_ep_idx)) {
		IPAERR("ep do not support filtering ep=%d\n", ep);
		return -EINVAL;
	}

	return 0;
}

static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep,
				 const struct ipa_flt_rule *rule, u8 add_rear,
				 u32 *rule_hdl)
@@ -1225,18 +1321,9 @@ static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep,

		return -EINVAL;
	}
	ipa_ep_idx = ipa3_get_ep_mapping(ep);
	if (ipa_ep_idx == IPA_FLT_TABLE_INDEX_NOT_FOUND) {
		IPAERR("ep not valid ep=%d\n", ep);
		return -EINVAL;
	}
	if (ipa3_ctx->ep[ipa_ep_idx].valid == 0)
		IPADBG("ep not connected ep_idx=%d\n", ipa_ep_idx);

	if (!ipa_is_ep_support_flt(ipa_ep_idx)) {
		IPAERR("ep do not support filtering ep=%d\n", ep);
	if (__ipa_add_flt_get_ep_idx(ep, &ipa_ep_idx))
		return -EINVAL;
	}

	tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][ip];
	IPADBG("add ep flt rule ip=%d ep=%d\n", ip, ep);
@@ -1300,6 +1387,99 @@ bail:
	return result;
}

/**
 * ipa3_add_flt_rule_after() - Add the specified filtering rules to SW after
 *  the rule which its handle is given and optionally commit to IPA HW
 *
 * Returns:	0 on success, negative on failure
 *
 * Note:	Should not be called from atomic context
 */
int ipa3_add_flt_rule_after(struct ipa_ioc_add_flt_rule_after *rules)
{
	int i;
	int result;
	struct ipa3_flt_tbl *tbl;
	int ipa_ep_idx;
	struct ipa3_flt_entry *entry;

	if (rules == NULL || rules->num_rules == 0 ||
			rules->ip >= IPA_IP_MAX) {
		IPAERR("bad parm\n");
		return -EINVAL;
	}

	if (rules->ep >= IPA_CLIENT_MAX) {
		IPAERR("bad parms ep=%d\n", rules->ep);
		return -EINVAL;
	}

	mutex_lock(&ipa3_ctx->lock);

	if (__ipa_add_flt_get_ep_idx(rules->ep, &ipa_ep_idx)) {
		result = -EINVAL;
		goto bail;
	}

	tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][rules->ip];

	entry = ipa3_id_find(rules->add_after_hdl);
	if (entry == NULL) {
		IPAERR("lookup failed\n");
		result = -EINVAL;
		goto bail;
	}

	if (entry->tbl != tbl) {
		IPAERR("given entry does not match the table\n");
		result = -EINVAL;
		goto bail;
	}

	if (tbl->sticky_rear)
		if (&entry->link == tbl->head_flt_rule_list.prev) {
			IPAERR("cannot add rule at end of a sticky table");
			result = -EINVAL;
			goto bail;
		}

	IPADBG("add ep flt rule ip=%d ep=%d after hdl %d\n",
			rules->ip, rules->ep, rules->add_after_hdl);

	/*
	 * we add all rules one after the other, if one insertion fails, it cuts
	 * the chain (all following will receive fail status) following calls to
	 * __ipa_add_flt_rule_after will fail (entry == NULL)
	 */

	for (i = 0; i < rules->num_rules; i++) {
		result = __ipa_add_flt_rule_after(tbl,
				&rules->rules[i].rule,
				&rules->rules[i].flt_rule_hdl,
				rules->ip,
				&entry);

		if (result) {
			IPAERR("failed to add flt rule %d\n", i);
			rules->rules[i].status = IPA_FLT_STATUS_OF_ADD_FAILED;
		} else {
			rules->rules[i].status = 0;
		}
	}

	if (rules->commit)
		if (ipa3_ctx->ctrl->ipa3_commit_flt(rules->ip)) {
			IPAERR("failed to commit flt rules\n");
			result = -EPERM;
			goto bail;
		}
	result = 0;
bail:
	mutex_unlock(&ipa3_ctx->lock);

	return result;
}

/**
 * ipa3_del_flt_rule() - Remove the specified filtering rules from SW and
 * optionally commit to IPA HW
+4 −0
Original line number Diff line number Diff line
@@ -1565,6 +1565,8 @@ int ipa3_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls);
 */
int ipa3_add_rt_rule(struct ipa_ioc_add_rt_rule *rules);

int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules);

int ipa3_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls);

int ipa3_commit_rt(enum ipa_ip_type ip);
@@ -1584,6 +1586,8 @@ int ipa3_mdfy_rt_rule(struct ipa_ioc_mdfy_rt_rule *rules);
 */
int ipa3_add_flt_rule(struct ipa_ioc_add_flt_rule *rules);

int ipa3_add_flt_rule_after(struct ipa_ioc_add_flt_rule_after *rules);

int ipa3_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls);

int ipa3_mdfy_flt_rule(struct ipa_ioc_mdfy_flt_rule *rules);
+218 −44
Original line number Diff line number Diff line
@@ -989,73 +989,73 @@ static int __ipa_del_rt_tbl(struct ipa3_rt_tbl *entry)
	return 0;
}

static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name,
		const struct ipa_rt_rule *rule, u8 at_rear, u32 *rule_hdl)
static int __ipa_rt_validate_hndls(const struct ipa_rt_rule *rule,
				struct ipa3_hdr_entry **hdr,
				struct ipa3_hdr_proc_ctx_entry **proc_ctx)
{
	struct ipa3_rt_tbl *tbl;
	struct ipa3_rt_entry *entry;
	struct ipa3_hdr_entry *hdr = NULL;
	struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL;
	int id;

	if (rule->hdr_hdl && rule->hdr_proc_ctx_hdl) {
		IPAERR("rule contains both hdr_hdl and hdr_proc_ctx_hdl\n");
		goto error;
		return -EPERM;
	}

	if (rule->hdr_hdl) {
		hdr = ipa3_id_find(rule->hdr_hdl);
		if ((hdr == NULL) || (hdr->cookie != IPA_COOKIE)) {
		*hdr = ipa3_id_find(rule->hdr_hdl);
		if ((*hdr == NULL) || ((*hdr)->cookie != IPA_COOKIE)) {
			IPAERR("rt rule does not point to valid hdr\n");
			goto error;
			return -EPERM;
		}
	} else if (rule->hdr_proc_ctx_hdl) {
		proc_ctx = ipa3_id_find(rule->hdr_proc_ctx_hdl);
		if ((proc_ctx == NULL) || (proc_ctx->cookie != IPA_COOKIE)) {
		*proc_ctx = ipa3_id_find(rule->hdr_proc_ctx_hdl);
		if ((*proc_ctx == NULL) ||
			((*proc_ctx)->cookie != IPA_COOKIE)) {

			IPAERR("rt rule does not point to valid proc ctx\n");
			goto error;
			return -EPERM;
		}
	}


	tbl = __ipa_add_rt_tbl(ip, name);
	if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) {
		IPAERR("failed adding rt tbl name=%s\n", name ? name : "");
		goto error;
	}
	/*
	 * do not allow any rules to be added at end of the "default" routing
	 * tables
	 */
	if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) &&
	    (tbl->rule_cnt > 0) && (at_rear != 0)) {
		IPAERR("cannot add rule at end of tbl rule_cnt=%d at_rear=%d\n",
		       tbl->rule_cnt, at_rear);
		goto error;
	return 0;
}

	entry = kmem_cache_zalloc(ipa3_ctx->rt_rule_cache, GFP_KERNEL);
	if (!entry) {
static int __ipa_create_rt_entry(struct ipa3_rt_entry **entry,
		const struct ipa_rt_rule *rule,
		struct ipa3_rt_tbl *tbl, struct ipa3_hdr_entry *hdr,
		struct ipa3_hdr_proc_ctx_entry *proc_ctx)
{
	int id;

	*entry = kmem_cache_zalloc(ipa3_ctx->rt_rule_cache, GFP_KERNEL);
	if (!*entry) {
		IPAERR("failed to alloc RT rule object\n");
		goto error;
	}
	INIT_LIST_HEAD(&entry->link);
	entry->cookie = IPA_COOKIE;
	entry->rule = *rule;
	entry->tbl = tbl;
	entry->hdr = hdr;
	entry->proc_ctx = proc_ctx;
	INIT_LIST_HEAD(&(*entry)->link);
	(*(entry))->cookie = IPA_COOKIE;
	(*(entry))->rule = *rule;
	(*(entry))->tbl = tbl;
	(*(entry))->hdr = hdr;
	(*(entry))->proc_ctx = proc_ctx;
	id = ipa3_alloc_rule_id(&tbl->rule_ids);
	if (id < 0) {
		IPAERR("failed to allocate rule id\n");
		WARN_ON(1);
		goto alloc_rule_id_fail;
	}
	entry->rule_id = id;
	if (at_rear)
		list_add_tail(&entry->link, &tbl->head_rt_rule_list);
	else
		list_add(&entry->link, &tbl->head_rt_rule_list);
	(*(entry))->rule_id = id;

	return 0;

alloc_rule_id_fail:
	kmem_cache_free(ipa3_ctx->rt_rule_cache, *entry);
error:
	return -EPERM;
}

static int __ipa_finish_rt_rule_add(struct ipa3_rt_entry *entry, u32 *rule_hdl,
		struct ipa3_rt_tbl *tbl)
{
	int id;

	tbl->rule_cnt++;
	if (entry->hdr)
		entry->hdr->ref_cnt++;
@@ -1077,9 +1077,87 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name,
ipa_insert_failed:
	idr_remove(&tbl->rule_ids, entry->rule_id);
	list_del(&entry->link);
alloc_rule_id_fail:
	kmem_cache_free(ipa3_ctx->rt_rule_cache, entry);
	return -EPERM;
}

static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name,
		const struct ipa_rt_rule *rule, u8 at_rear, u32 *rule_hdl)
{
	struct ipa3_rt_tbl *tbl;
	struct ipa3_rt_entry *entry;
	struct ipa3_hdr_entry *hdr = NULL;
	struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL;

	if (__ipa_rt_validate_hndls(rule, &hdr, &proc_ctx))
		goto error;


	tbl = __ipa_add_rt_tbl(ip, name);
	if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) {
		IPAERR("failed adding rt tbl name = %s\n",
			name ? name : "");
		goto error;
	}
	/*
	 * do not allow any rules to be added at end of the "default" routing
	 * tables
	 */
	if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) &&
	    (tbl->rule_cnt > 0) && (at_rear != 0)) {
		IPAERR("cannot add rule at end of tbl rule_cnt=%d at_rear=%d\n",
		       tbl->rule_cnt, at_rear);
		goto error;
	}

	if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx))
		goto error;

	if (at_rear)
		list_add_tail(&entry->link, &tbl->head_rt_rule_list);
	else
		list_add(&entry->link, &tbl->head_rt_rule_list);

	if (__ipa_finish_rt_rule_add(entry, rule_hdl, tbl))
		goto error;

	return 0;

error:
	return -EPERM;
}

static int __ipa_add_rt_rule_after(struct ipa3_rt_tbl *tbl,
		const struct ipa_rt_rule *rule, u32 *rule_hdl,
		struct ipa3_rt_entry **add_after_entry)
{
	struct ipa3_rt_entry *entry;
	struct ipa3_hdr_entry *hdr = NULL;
	struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL;

	if (!*add_after_entry)
		goto error;

	if (__ipa_rt_validate_hndls(rule, &hdr, &proc_ctx))
		goto error;

	if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx))
		goto error;

	list_add(&entry->link, &((*add_after_entry)->link));

	if (__ipa_finish_rt_rule_add(entry, rule_hdl, tbl))
		goto error;

	/*
	 * prepare for next insertion
	 */
	*add_after_entry = entry;

	return 0;

error:
	*add_after_entry = NULL;
	return -EPERM;
}

@@ -1127,6 +1205,102 @@ bail:
	return ret;
}

/**
 * ipa3_add_rt_rule_after() - Add the given routing rules after the
 * specified rule to SW and optionally commit to IPA HW
 * @rules:	[inout] set of routing rules to add + handle where to add
 *
 * Returns:	0 on success, negative on failure
 *
 * Note:	Should not be called from atomic context
 */
int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules)
{
	int i;
	int ret = 0;
	struct ipa3_rt_tbl *tbl = NULL;
	struct ipa3_rt_entry *entry = NULL;

	if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) {
		IPAERR("bad parm\n");
		return -EINVAL;
	}

	mutex_lock(&ipa3_ctx->lock);

	tbl = __ipa3_find_rt_tbl(rules->ip, rules->rt_tbl_name);
	if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) {
		IPAERR("failed finding rt tbl name = %s\n",
			rules->rt_tbl_name ? rules->rt_tbl_name : "");
		ret = -EINVAL;
		goto bail;
	}

	if (tbl->rule_cnt <= 0) {
		IPAERR("tbl->rule_cnt <= 0");
		ret = -EINVAL;
		goto bail;
	}

	entry = ipa3_id_find(rules->add_after_hdl);
	if (!entry) {
		IPAERR("failed finding rule %d in rt tbls\n",
			rules->add_after_hdl);
		ret = -EINVAL;
		goto bail;
	}

	if (entry->tbl != tbl) {
		IPAERR("given rt rule does not match the table\n");
		ret = -EINVAL;
		goto bail;
	}

	/*
	 * do not allow any rules to be added at end of the "default" routing
	 * tables
	 */
	if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) &&
			(&entry->link == tbl->head_rt_rule_list.prev)) {
		IPAERR("cannot add rule at end of tbl rule_cnt=%d\n",
			tbl->rule_cnt);
		ret = -EINVAL;
		goto bail;
	}

	/*
	 * we add all rules one after the other, if one insertion fails, it cuts
	 * the chain (all following will receive fail status) following calls to
	 * __ipa_add_rt_rule_after will fail (entry == NULL)
	 */

	for (i = 0; i < rules->num_rules; i++) {
		if (__ipa_add_rt_rule_after(tbl,
					&rules->rules[i].rule,
					&rules->rules[i].rt_rule_hdl,
					&entry)) {
			IPAERR("failed to add rt rule %d\n", i);
			rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED;
		} else {
			rules->rules[i].status = 0;
		}
	}

	if (rules->commit)
		if (ipa3_ctx->ctrl->ipa3_commit_rt(rules->ip)) {
			IPAERR("failed to commit\n");
			ret = -EPERM;
			goto bail;
		}

	ret = 0;
	goto bail;

bail:
	mutex_unlock(&ipa3_ctx->lock);
	return ret;
}

int __ipa3_del_rt_rule(u32 rule_hdl)
{
	struct ipa3_rt_entry *entry;
+52 −1
Original line number Diff line number Diff line
@@ -65,7 +65,9 @@
#define IPA_IOCTL_ADD_HDR_PROC_CTX 40
#define IPA_IOCTL_DEL_HDR_PROC_CTX 41
#define IPA_IOCTL_MDFY_RT_RULE 42
#define IPA_IOCTL_MAX 43
#define IPA_IOCTL_ADD_RT_RULE_AFTER 43
#define IPA_IOCTL_ADD_FLT_RULE_AFTER 44
#define IPA_IOCTL_MAX 45

/**
 * max size of the header to be inserted
@@ -867,6 +869,28 @@ struct ipa_ioc_add_rt_rule {
	struct ipa_rt_rule_add rules[0];
};

/**
 * struct ipa_ioc_add_rt_rule_after - routing rule addition after a specific
 * rule parameters(supports multiple rules and commit);
 *
 * all rules MUST be added to same table
 * @commit: should rules be written to IPA HW also?
 * @ip: IP family of rule
 * @rt_tbl_name: name of routing table resource
 * @num_rules: number of routing rules that follow
 * @add_after_hdl: the rules will be added after this specific rule
 * @ipa_rt_rule_add rules: all rules need to go back to back here, no pointers
 *			   at_rear field will be ignored when using this IOCTL
 */
struct ipa_ioc_add_rt_rule_after {
	uint8_t commit;
	enum ipa_ip_type ip;
	char rt_tbl_name[IPA_RESOURCE_NAME_MAX];
	uint8_t num_rules;
	uint32_t add_after_hdl;
	struct ipa_rt_rule_add rules[0];
};

/**
 * struct ipa_rt_rule_mdfy - routing rule descriptor includes
 * in and out parameters
@@ -978,6 +1002,27 @@ struct ipa_ioc_add_flt_rule {
	struct ipa_flt_rule_add rules[0];
};

/**
 * struct ipa_ioc_add_flt_rule_after - filtering rule addition after specific
 * rule parameters (supports multiple rules and commit)
 * all rules MUST be added to same table
 * @commit: should rules be written to IPA HW also?
 * @ip: IP family of rule
 * @ep:	which "clients" pipe does this rule apply to?
 * @num_rules: number of filtering rules that follow
 * @add_after_hdl: rules will be added after the rule with this handle
 * @rules: all rules need to go back to back here, no pointers. at rear field
 *	   is ignored when using this IOCTL
 */
struct ipa_ioc_add_flt_rule_after {
	uint8_t commit;
	enum ipa_ip_type ip;
	enum ipa_client_type ep;
	uint8_t num_rules;
	uint32_t add_after_hdl;
	struct ipa_flt_rule_add rules[0];
};

/**
 * struct ipa_flt_rule_mdfy - filtering rule descriptor includes
 * in and out parameters
@@ -1378,12 +1423,18 @@ struct ipa_ioc_write_qmapid {
#define IPA_IOC_ADD_RT_RULE _IOWR(IPA_IOC_MAGIC, \
					IPA_IOCTL_ADD_RT_RULE, \
					struct ipa_ioc_add_rt_rule *)
#define IPA_IOC_ADD_RT_RULE_AFTER _IOWR(IPA_IOC_MAGIC, \
					IPA_IOCTL_ADD_RT_RULE_AFTER, \
					struct ipa_ioc_add_rt_rule_after *)
#define IPA_IOC_DEL_RT_RULE _IOWR(IPA_IOC_MAGIC, \
					IPA_IOCTL_DEL_RT_RULE, \
					struct ipa_ioc_del_rt_rule *)
#define IPA_IOC_ADD_FLT_RULE _IOWR(IPA_IOC_MAGIC, \
					IPA_IOCTL_ADD_FLT_RULE, \
					struct ipa_ioc_add_flt_rule *)
#define IPA_IOC_ADD_FLT_RULE_AFTER _IOWR(IPA_IOC_MAGIC, \
					IPA_IOCTL_ADD_FLT_RULE_AFTER, \
					struct ipa_ioc_add_flt_rule_after *)
#define IPA_IOC_DEL_FLT_RULE _IOWR(IPA_IOC_MAGIC, \
					IPA_IOCTL_DEL_FLT_RULE, \
					struct ipa_ioc_del_flt_rule *)