18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * net/sched/ematch.c		Extended Match API
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Authors:	Thomas Graf <tgraf@suug.ch>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * ==========================================================================
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * An extended match (ematch) is a small classification tool not worth
108c2ecf20Sopenharmony_ci * writing a full classifier for. Ematches can be interconnected to form
118c2ecf20Sopenharmony_ci * a logic expression and get attached to classifiers to extend their
128c2ecf20Sopenharmony_ci * functionatlity.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * The userspace part transforms the logic expressions into an array
158c2ecf20Sopenharmony_ci * consisting of multiple sequences of interconnected ematches separated
168c2ecf20Sopenharmony_ci * by markers. Precedence is implemented by a special ematch kind
178c2ecf20Sopenharmony_ci * referencing a sequence beyond the marker of the current sequence
188c2ecf20Sopenharmony_ci * causing the current position in the sequence to be pushed onto a stack
198c2ecf20Sopenharmony_ci * to allow the current position to be overwritten by the position referenced
208c2ecf20Sopenharmony_ci * in the special ematch. Matching continues in the new sequence until a
218c2ecf20Sopenharmony_ci * marker is reached causing the position to be restored from the stack.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * Example:
248c2ecf20Sopenharmony_ci *          A AND (B1 OR B2) AND C AND D
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci *              ------->-PUSH-------
278c2ecf20Sopenharmony_ci *    -->--    /         -->--      \   -->--
288c2ecf20Sopenharmony_ci *   /     \  /         /     \      \ /     \
298c2ecf20Sopenharmony_ci * +-------+-------+-------+-------+-------+--------+
308c2ecf20Sopenharmony_ci * | A AND | B AND | C AND | D END | B1 OR | B2 END |
318c2ecf20Sopenharmony_ci * +-------+-------+-------+-------+-------+--------+
328c2ecf20Sopenharmony_ci *                    \                      /
338c2ecf20Sopenharmony_ci *                     --------<-POP---------
348c2ecf20Sopenharmony_ci *
358c2ecf20Sopenharmony_ci * where B is a virtual ematch referencing to sequence starting with B1.
368c2ecf20Sopenharmony_ci *
378c2ecf20Sopenharmony_ci * ==========================================================================
388c2ecf20Sopenharmony_ci *
398c2ecf20Sopenharmony_ci * How to write an ematch in 60 seconds
408c2ecf20Sopenharmony_ci * ------------------------------------
418c2ecf20Sopenharmony_ci *
428c2ecf20Sopenharmony_ci *   1) Provide a matcher function:
438c2ecf20Sopenharmony_ci *      static int my_match(struct sk_buff *skb, struct tcf_ematch *m,
448c2ecf20Sopenharmony_ci *                          struct tcf_pkt_info *info)
458c2ecf20Sopenharmony_ci *      {
468c2ecf20Sopenharmony_ci *      	struct mydata *d = (struct mydata *) m->data;
478c2ecf20Sopenharmony_ci *
488c2ecf20Sopenharmony_ci *      	if (...matching goes here...)
498c2ecf20Sopenharmony_ci *      		return 1;
508c2ecf20Sopenharmony_ci *      	else
518c2ecf20Sopenharmony_ci *      		return 0;
528c2ecf20Sopenharmony_ci *      }
538c2ecf20Sopenharmony_ci *
548c2ecf20Sopenharmony_ci *   2) Fill out a struct tcf_ematch_ops:
558c2ecf20Sopenharmony_ci *      static struct tcf_ematch_ops my_ops = {
568c2ecf20Sopenharmony_ci *      	.kind = unique id,
578c2ecf20Sopenharmony_ci *      	.datalen = sizeof(struct mydata),
588c2ecf20Sopenharmony_ci *      	.match = my_match,
598c2ecf20Sopenharmony_ci *      	.owner = THIS_MODULE,
608c2ecf20Sopenharmony_ci *      };
618c2ecf20Sopenharmony_ci *
628c2ecf20Sopenharmony_ci *   3) Register/Unregister your ematch:
638c2ecf20Sopenharmony_ci *      static int __init init_my_ematch(void)
648c2ecf20Sopenharmony_ci *      {
658c2ecf20Sopenharmony_ci *      	return tcf_em_register(&my_ops);
668c2ecf20Sopenharmony_ci *      }
678c2ecf20Sopenharmony_ci *
688c2ecf20Sopenharmony_ci *      static void __exit exit_my_ematch(void)
698c2ecf20Sopenharmony_ci *      {
708c2ecf20Sopenharmony_ci *      	tcf_em_unregister(&my_ops);
718c2ecf20Sopenharmony_ci *      }
728c2ecf20Sopenharmony_ci *
738c2ecf20Sopenharmony_ci *      module_init(init_my_ematch);
748c2ecf20Sopenharmony_ci *      module_exit(exit_my_ematch);
758c2ecf20Sopenharmony_ci *
768c2ecf20Sopenharmony_ci *   4) By now you should have two more seconds left, barely enough to
778c2ecf20Sopenharmony_ci *      open up a beer to watch the compilation going.
788c2ecf20Sopenharmony_ci */
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci#include <linux/module.h>
818c2ecf20Sopenharmony_ci#include <linux/slab.h>
828c2ecf20Sopenharmony_ci#include <linux/types.h>
838c2ecf20Sopenharmony_ci#include <linux/kernel.h>
848c2ecf20Sopenharmony_ci#include <linux/errno.h>
858c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h>
868c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
878c2ecf20Sopenharmony_ci#include <net/pkt_cls.h>
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic LIST_HEAD(ematch_ops);
908c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(ematch_mod_lock);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic struct tcf_ematch_ops *tcf_em_lookup(u16 kind)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct tcf_ematch_ops *e = NULL;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	read_lock(&ematch_mod_lock);
978c2ecf20Sopenharmony_ci	list_for_each_entry(e, &ematch_ops, link) {
988c2ecf20Sopenharmony_ci		if (kind == e->kind) {
998c2ecf20Sopenharmony_ci			if (!try_module_get(e->owner))
1008c2ecf20Sopenharmony_ci				e = NULL;
1018c2ecf20Sopenharmony_ci			read_unlock(&ematch_mod_lock);
1028c2ecf20Sopenharmony_ci			return e;
1038c2ecf20Sopenharmony_ci		}
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci	read_unlock(&ematch_mod_lock);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	return NULL;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci/**
1118c2ecf20Sopenharmony_ci * tcf_em_register - register an extended match
1128c2ecf20Sopenharmony_ci *
1138c2ecf20Sopenharmony_ci * @ops: ematch operations lookup table
1148c2ecf20Sopenharmony_ci *
1158c2ecf20Sopenharmony_ci * This function must be called by ematches to announce their presence.
1168c2ecf20Sopenharmony_ci * The given @ops must have kind set to a unique identifier and the
1178c2ecf20Sopenharmony_ci * callback match() must be implemented. All other callbacks are optional
1188c2ecf20Sopenharmony_ci * and a fallback implementation is used instead.
1198c2ecf20Sopenharmony_ci *
1208c2ecf20Sopenharmony_ci * Returns -EEXISTS if an ematch of the same kind has already registered.
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_ciint tcf_em_register(struct tcf_ematch_ops *ops)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	int err = -EEXIST;
1258c2ecf20Sopenharmony_ci	struct tcf_ematch_ops *e;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (ops->match == NULL)
1288c2ecf20Sopenharmony_ci		return -EINVAL;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	write_lock(&ematch_mod_lock);
1318c2ecf20Sopenharmony_ci	list_for_each_entry(e, &ematch_ops, link)
1328c2ecf20Sopenharmony_ci		if (ops->kind == e->kind)
1338c2ecf20Sopenharmony_ci			goto errout;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	list_add_tail(&ops->link, &ematch_ops);
1368c2ecf20Sopenharmony_ci	err = 0;
1378c2ecf20Sopenharmony_cierrout:
1388c2ecf20Sopenharmony_ci	write_unlock(&ematch_mod_lock);
1398c2ecf20Sopenharmony_ci	return err;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcf_em_register);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci/**
1448c2ecf20Sopenharmony_ci * tcf_em_unregister - unregster and extended match
1458c2ecf20Sopenharmony_ci *
1468c2ecf20Sopenharmony_ci * @ops: ematch operations lookup table
1478c2ecf20Sopenharmony_ci *
1488c2ecf20Sopenharmony_ci * This function must be called by ematches to announce their disappearance
1498c2ecf20Sopenharmony_ci * for examples when the module gets unloaded. The @ops parameter must be
1508c2ecf20Sopenharmony_ci * the same as the one used for registration.
1518c2ecf20Sopenharmony_ci *
1528c2ecf20Sopenharmony_ci * Returns -ENOENT if no matching ematch was found.
1538c2ecf20Sopenharmony_ci */
1548c2ecf20Sopenharmony_civoid tcf_em_unregister(struct tcf_ematch_ops *ops)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	write_lock(&ematch_mod_lock);
1578c2ecf20Sopenharmony_ci	list_del(&ops->link);
1588c2ecf20Sopenharmony_ci	write_unlock(&ematch_mod_lock);
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcf_em_unregister);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic inline struct tcf_ematch *tcf_em_get_match(struct tcf_ematch_tree *tree,
1638c2ecf20Sopenharmony_ci						  int index)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	return &tree->matches[index];
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic int tcf_em_validate(struct tcf_proto *tp,
1708c2ecf20Sopenharmony_ci			   struct tcf_ematch_tree_hdr *tree_hdr,
1718c2ecf20Sopenharmony_ci			   struct tcf_ematch *em, struct nlattr *nla, int idx)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	int err = -EINVAL;
1748c2ecf20Sopenharmony_ci	struct tcf_ematch_hdr *em_hdr = nla_data(nla);
1758c2ecf20Sopenharmony_ci	int data_len = nla_len(nla) - sizeof(*em_hdr);
1768c2ecf20Sopenharmony_ci	void *data = (void *) em_hdr + sizeof(*em_hdr);
1778c2ecf20Sopenharmony_ci	struct net *net = tp->chain->block->net;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (!TCF_EM_REL_VALID(em_hdr->flags))
1808c2ecf20Sopenharmony_ci		goto errout;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (em_hdr->kind == TCF_EM_CONTAINER) {
1838c2ecf20Sopenharmony_ci		/* Special ematch called "container", carries an index
1848c2ecf20Sopenharmony_ci		 * referencing an external ematch sequence.
1858c2ecf20Sopenharmony_ci		 */
1868c2ecf20Sopenharmony_ci		u32 ref;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci		if (data_len < sizeof(ref))
1898c2ecf20Sopenharmony_ci			goto errout;
1908c2ecf20Sopenharmony_ci		ref = *(u32 *) data;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci		if (ref >= tree_hdr->nmatches)
1938c2ecf20Sopenharmony_ci			goto errout;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci		/* We do not allow backward jumps to avoid loops and jumps
1968c2ecf20Sopenharmony_ci		 * to our own position are of course illegal.
1978c2ecf20Sopenharmony_ci		 */
1988c2ecf20Sopenharmony_ci		if (ref <= idx)
1998c2ecf20Sopenharmony_ci			goto errout;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci		em->data = ref;
2038c2ecf20Sopenharmony_ci	} else {
2048c2ecf20Sopenharmony_ci		/* Note: This lookup will increase the module refcnt
2058c2ecf20Sopenharmony_ci		 * of the ematch module referenced. In case of a failure,
2068c2ecf20Sopenharmony_ci		 * a destroy function is called by the underlying layer
2078c2ecf20Sopenharmony_ci		 * which automatically releases the reference again, therefore
2088c2ecf20Sopenharmony_ci		 * the module MUST not be given back under any circumstances
2098c2ecf20Sopenharmony_ci		 * here. Be aware, the destroy function assumes that the
2108c2ecf20Sopenharmony_ci		 * module is held if the ops field is non zero.
2118c2ecf20Sopenharmony_ci		 */
2128c2ecf20Sopenharmony_ci		em->ops = tcf_em_lookup(em_hdr->kind);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci		if (em->ops == NULL) {
2158c2ecf20Sopenharmony_ci			err = -ENOENT;
2168c2ecf20Sopenharmony_ci#ifdef CONFIG_MODULES
2178c2ecf20Sopenharmony_ci			__rtnl_unlock();
2188c2ecf20Sopenharmony_ci			request_module("ematch-kind-%u", em_hdr->kind);
2198c2ecf20Sopenharmony_ci			rtnl_lock();
2208c2ecf20Sopenharmony_ci			em->ops = tcf_em_lookup(em_hdr->kind);
2218c2ecf20Sopenharmony_ci			if (em->ops) {
2228c2ecf20Sopenharmony_ci				/* We dropped the RTNL mutex in order to
2238c2ecf20Sopenharmony_ci				 * perform the module load. Tell the caller
2248c2ecf20Sopenharmony_ci				 * to replay the request.
2258c2ecf20Sopenharmony_ci				 */
2268c2ecf20Sopenharmony_ci				module_put(em->ops->owner);
2278c2ecf20Sopenharmony_ci				em->ops = NULL;
2288c2ecf20Sopenharmony_ci				err = -EAGAIN;
2298c2ecf20Sopenharmony_ci			}
2308c2ecf20Sopenharmony_ci#endif
2318c2ecf20Sopenharmony_ci			goto errout;
2328c2ecf20Sopenharmony_ci		}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci		/* ematch module provides expected length of data, so we
2358c2ecf20Sopenharmony_ci		 * can do a basic sanity check.
2368c2ecf20Sopenharmony_ci		 */
2378c2ecf20Sopenharmony_ci		if (em->ops->datalen && data_len < em->ops->datalen)
2388c2ecf20Sopenharmony_ci			goto errout;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci		if (em->ops->change) {
2418c2ecf20Sopenharmony_ci			err = -EINVAL;
2428c2ecf20Sopenharmony_ci			if (em_hdr->flags & TCF_EM_SIMPLE)
2438c2ecf20Sopenharmony_ci				goto errout;
2448c2ecf20Sopenharmony_ci			err = em->ops->change(net, data, data_len, em);
2458c2ecf20Sopenharmony_ci			if (err < 0)
2468c2ecf20Sopenharmony_ci				goto errout;
2478c2ecf20Sopenharmony_ci		} else if (data_len > 0) {
2488c2ecf20Sopenharmony_ci			/* ematch module doesn't provide an own change
2498c2ecf20Sopenharmony_ci			 * procedure and expects us to allocate and copy
2508c2ecf20Sopenharmony_ci			 * the ematch data.
2518c2ecf20Sopenharmony_ci			 *
2528c2ecf20Sopenharmony_ci			 * TCF_EM_SIMPLE may be specified stating that the
2538c2ecf20Sopenharmony_ci			 * data only consists of a u32 integer and the module
2548c2ecf20Sopenharmony_ci			 * does not expected a memory reference but rather
2558c2ecf20Sopenharmony_ci			 * the value carried.
2568c2ecf20Sopenharmony_ci			 */
2578c2ecf20Sopenharmony_ci			if (em_hdr->flags & TCF_EM_SIMPLE) {
2588c2ecf20Sopenharmony_ci				if (em->ops->datalen > 0)
2598c2ecf20Sopenharmony_ci					goto errout;
2608c2ecf20Sopenharmony_ci				if (data_len < sizeof(u32))
2618c2ecf20Sopenharmony_ci					goto errout;
2628c2ecf20Sopenharmony_ci				em->data = *(u32 *) data;
2638c2ecf20Sopenharmony_ci			} else {
2648c2ecf20Sopenharmony_ci				void *v = kmemdup(data, data_len, GFP_KERNEL);
2658c2ecf20Sopenharmony_ci				if (v == NULL) {
2668c2ecf20Sopenharmony_ci					err = -ENOBUFS;
2678c2ecf20Sopenharmony_ci					goto errout;
2688c2ecf20Sopenharmony_ci				}
2698c2ecf20Sopenharmony_ci				em->data = (unsigned long) v;
2708c2ecf20Sopenharmony_ci			}
2718c2ecf20Sopenharmony_ci			em->datalen = data_len;
2728c2ecf20Sopenharmony_ci		}
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	em->matchid = em_hdr->matchid;
2768c2ecf20Sopenharmony_ci	em->flags = em_hdr->flags;
2778c2ecf20Sopenharmony_ci	em->net = net;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	err = 0;
2808c2ecf20Sopenharmony_cierrout:
2818c2ecf20Sopenharmony_ci	return err;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic const struct nla_policy em_policy[TCA_EMATCH_TREE_MAX + 1] = {
2858c2ecf20Sopenharmony_ci	[TCA_EMATCH_TREE_HDR]	= { .len = sizeof(struct tcf_ematch_tree_hdr) },
2868c2ecf20Sopenharmony_ci	[TCA_EMATCH_TREE_LIST]	= { .type = NLA_NESTED },
2878c2ecf20Sopenharmony_ci};
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci/**
2908c2ecf20Sopenharmony_ci * tcf_em_tree_validate - validate ematch config TLV and build ematch tree
2918c2ecf20Sopenharmony_ci *
2928c2ecf20Sopenharmony_ci * @tp: classifier kind handle
2938c2ecf20Sopenharmony_ci * @nla: ematch tree configuration TLV
2948c2ecf20Sopenharmony_ci * @tree: destination ematch tree variable to store the resulting
2958c2ecf20Sopenharmony_ci *        ematch tree.
2968c2ecf20Sopenharmony_ci *
2978c2ecf20Sopenharmony_ci * This function validates the given configuration TLV @nla and builds an
2988c2ecf20Sopenharmony_ci * ematch tree in @tree. The resulting tree must later be copied into
2998c2ecf20Sopenharmony_ci * the private classifier data using tcf_em_tree_change(). You MUST NOT
3008c2ecf20Sopenharmony_ci * provide the ematch tree variable of the private classifier data directly,
3018c2ecf20Sopenharmony_ci * the changes would not be locked properly.
3028c2ecf20Sopenharmony_ci *
3038c2ecf20Sopenharmony_ci * Returns a negative error code if the configuration TLV contains errors.
3048c2ecf20Sopenharmony_ci */
3058c2ecf20Sopenharmony_ciint tcf_em_tree_validate(struct tcf_proto *tp, struct nlattr *nla,
3068c2ecf20Sopenharmony_ci			 struct tcf_ematch_tree *tree)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	int idx, list_len, matches_len, err;
3098c2ecf20Sopenharmony_ci	struct nlattr *tb[TCA_EMATCH_TREE_MAX + 1];
3108c2ecf20Sopenharmony_ci	struct nlattr *rt_match, *rt_hdr, *rt_list;
3118c2ecf20Sopenharmony_ci	struct tcf_ematch_tree_hdr *tree_hdr;
3128c2ecf20Sopenharmony_ci	struct tcf_ematch *em;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	memset(tree, 0, sizeof(*tree));
3158c2ecf20Sopenharmony_ci	if (!nla)
3168c2ecf20Sopenharmony_ci		return 0;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	err = nla_parse_nested_deprecated(tb, TCA_EMATCH_TREE_MAX, nla,
3198c2ecf20Sopenharmony_ci					  em_policy, NULL);
3208c2ecf20Sopenharmony_ci	if (err < 0)
3218c2ecf20Sopenharmony_ci		goto errout;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	err = -EINVAL;
3248c2ecf20Sopenharmony_ci	rt_hdr = tb[TCA_EMATCH_TREE_HDR];
3258c2ecf20Sopenharmony_ci	rt_list = tb[TCA_EMATCH_TREE_LIST];
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	if (rt_hdr == NULL || rt_list == NULL)
3288c2ecf20Sopenharmony_ci		goto errout;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	tree_hdr = nla_data(rt_hdr);
3318c2ecf20Sopenharmony_ci	memcpy(&tree->hdr, tree_hdr, sizeof(*tree_hdr));
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	rt_match = nla_data(rt_list);
3348c2ecf20Sopenharmony_ci	list_len = nla_len(rt_list);
3358c2ecf20Sopenharmony_ci	matches_len = tree_hdr->nmatches * sizeof(*em);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	tree->matches = kzalloc(matches_len, GFP_KERNEL);
3388c2ecf20Sopenharmony_ci	if (tree->matches == NULL)
3398c2ecf20Sopenharmony_ci		goto errout;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	/* We do not use nla_parse_nested here because the maximum
3428c2ecf20Sopenharmony_ci	 * number of attributes is unknown. This saves us the allocation
3438c2ecf20Sopenharmony_ci	 * for a tb buffer which would serve no purpose at all.
3448c2ecf20Sopenharmony_ci	 *
3458c2ecf20Sopenharmony_ci	 * The array of rt attributes is parsed in the order as they are
3468c2ecf20Sopenharmony_ci	 * provided, their type must be incremental from 1 to n. Even
3478c2ecf20Sopenharmony_ci	 * if it does not serve any real purpose, a failure of sticking
3488c2ecf20Sopenharmony_ci	 * to this policy will result in parsing failure.
3498c2ecf20Sopenharmony_ci	 */
3508c2ecf20Sopenharmony_ci	for (idx = 0; nla_ok(rt_match, list_len); idx++) {
3518c2ecf20Sopenharmony_ci		err = -EINVAL;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci		if (rt_match->nla_type != (idx + 1))
3548c2ecf20Sopenharmony_ci			goto errout_abort;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci		if (idx >= tree_hdr->nmatches)
3578c2ecf20Sopenharmony_ci			goto errout_abort;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci		if (nla_len(rt_match) < sizeof(struct tcf_ematch_hdr))
3608c2ecf20Sopenharmony_ci			goto errout_abort;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci		em = tcf_em_get_match(tree, idx);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci		err = tcf_em_validate(tp, tree_hdr, em, rt_match, idx);
3658c2ecf20Sopenharmony_ci		if (err < 0)
3668c2ecf20Sopenharmony_ci			goto errout_abort;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci		rt_match = nla_next(rt_match, &list_len);
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	/* Check if the number of matches provided by userspace actually
3728c2ecf20Sopenharmony_ci	 * complies with the array of matches. The number was used for
3738c2ecf20Sopenharmony_ci	 * the validation of references and a mismatch could lead to
3748c2ecf20Sopenharmony_ci	 * undefined references during the matching process.
3758c2ecf20Sopenharmony_ci	 */
3768c2ecf20Sopenharmony_ci	if (idx != tree_hdr->nmatches) {
3778c2ecf20Sopenharmony_ci		err = -EINVAL;
3788c2ecf20Sopenharmony_ci		goto errout_abort;
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	err = 0;
3828c2ecf20Sopenharmony_cierrout:
3838c2ecf20Sopenharmony_ci	return err;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cierrout_abort:
3868c2ecf20Sopenharmony_ci	tcf_em_tree_destroy(tree);
3878c2ecf20Sopenharmony_ci	return err;
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcf_em_tree_validate);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci/**
3928c2ecf20Sopenharmony_ci * tcf_em_tree_destroy - destroy an ematch tree
3938c2ecf20Sopenharmony_ci *
3948c2ecf20Sopenharmony_ci * @tree: ematch tree to be deleted
3958c2ecf20Sopenharmony_ci *
3968c2ecf20Sopenharmony_ci * This functions destroys an ematch tree previously created by
3978c2ecf20Sopenharmony_ci * tcf_em_tree_validate()/tcf_em_tree_change(). You must ensure that
3988c2ecf20Sopenharmony_ci * the ematch tree is not in use before calling this function.
3998c2ecf20Sopenharmony_ci */
4008c2ecf20Sopenharmony_civoid tcf_em_tree_destroy(struct tcf_ematch_tree *tree)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	int i;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	if (tree->matches == NULL)
4058c2ecf20Sopenharmony_ci		return;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	for (i = 0; i < tree->hdr.nmatches; i++) {
4088c2ecf20Sopenharmony_ci		struct tcf_ematch *em = tcf_em_get_match(tree, i);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci		if (em->ops) {
4118c2ecf20Sopenharmony_ci			if (em->ops->destroy)
4128c2ecf20Sopenharmony_ci				em->ops->destroy(em);
4138c2ecf20Sopenharmony_ci			else if (!tcf_em_is_simple(em))
4148c2ecf20Sopenharmony_ci				kfree((void *) em->data);
4158c2ecf20Sopenharmony_ci			module_put(em->ops->owner);
4168c2ecf20Sopenharmony_ci		}
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	tree->hdr.nmatches = 0;
4208c2ecf20Sopenharmony_ci	kfree(tree->matches);
4218c2ecf20Sopenharmony_ci	tree->matches = NULL;
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcf_em_tree_destroy);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci/**
4268c2ecf20Sopenharmony_ci * tcf_em_tree_dump - dump ematch tree into a rtnl message
4278c2ecf20Sopenharmony_ci *
4288c2ecf20Sopenharmony_ci * @skb: skb holding the rtnl message
4298c2ecf20Sopenharmony_ci * @tree: ematch tree to be dumped
4308c2ecf20Sopenharmony_ci * @tlv: TLV type to be used to encapsulate the tree
4318c2ecf20Sopenharmony_ci *
4328c2ecf20Sopenharmony_ci * This function dumps a ematch tree into a rtnl message. It is valid to
4338c2ecf20Sopenharmony_ci * call this function while the ematch tree is in use.
4348c2ecf20Sopenharmony_ci *
4358c2ecf20Sopenharmony_ci * Returns -1 if the skb tailroom is insufficient.
4368c2ecf20Sopenharmony_ci */
4378c2ecf20Sopenharmony_ciint tcf_em_tree_dump(struct sk_buff *skb, struct tcf_ematch_tree *tree, int tlv)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	int i;
4408c2ecf20Sopenharmony_ci	u8 *tail;
4418c2ecf20Sopenharmony_ci	struct nlattr *top_start;
4428c2ecf20Sopenharmony_ci	struct nlattr *list_start;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	top_start = nla_nest_start_noflag(skb, tlv);
4458c2ecf20Sopenharmony_ci	if (top_start == NULL)
4468c2ecf20Sopenharmony_ci		goto nla_put_failure;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	if (nla_put(skb, TCA_EMATCH_TREE_HDR, sizeof(tree->hdr), &tree->hdr))
4498c2ecf20Sopenharmony_ci		goto nla_put_failure;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	list_start = nla_nest_start_noflag(skb, TCA_EMATCH_TREE_LIST);
4528c2ecf20Sopenharmony_ci	if (list_start == NULL)
4538c2ecf20Sopenharmony_ci		goto nla_put_failure;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	tail = skb_tail_pointer(skb);
4568c2ecf20Sopenharmony_ci	for (i = 0; i < tree->hdr.nmatches; i++) {
4578c2ecf20Sopenharmony_ci		struct nlattr *match_start = (struct nlattr *)tail;
4588c2ecf20Sopenharmony_ci		struct tcf_ematch *em = tcf_em_get_match(tree, i);
4598c2ecf20Sopenharmony_ci		struct tcf_ematch_hdr em_hdr = {
4608c2ecf20Sopenharmony_ci			.kind = em->ops ? em->ops->kind : TCF_EM_CONTAINER,
4618c2ecf20Sopenharmony_ci			.matchid = em->matchid,
4628c2ecf20Sopenharmony_ci			.flags = em->flags
4638c2ecf20Sopenharmony_ci		};
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci		if (nla_put(skb, i + 1, sizeof(em_hdr), &em_hdr))
4668c2ecf20Sopenharmony_ci			goto nla_put_failure;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci		if (em->ops && em->ops->dump) {
4698c2ecf20Sopenharmony_ci			if (em->ops->dump(skb, em) < 0)
4708c2ecf20Sopenharmony_ci				goto nla_put_failure;
4718c2ecf20Sopenharmony_ci		} else if (tcf_em_is_container(em) || tcf_em_is_simple(em)) {
4728c2ecf20Sopenharmony_ci			u32 u = em->data;
4738c2ecf20Sopenharmony_ci			nla_put_nohdr(skb, sizeof(u), &u);
4748c2ecf20Sopenharmony_ci		} else if (em->datalen > 0)
4758c2ecf20Sopenharmony_ci			nla_put_nohdr(skb, em->datalen, (void *) em->data);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci		tail = skb_tail_pointer(skb);
4788c2ecf20Sopenharmony_ci		match_start->nla_len = tail - (u8 *)match_start;
4798c2ecf20Sopenharmony_ci	}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	nla_nest_end(skb, list_start);
4828c2ecf20Sopenharmony_ci	nla_nest_end(skb, top_start);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	return 0;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cinla_put_failure:
4878c2ecf20Sopenharmony_ci	return -1;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcf_em_tree_dump);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistatic inline int tcf_em_match(struct sk_buff *skb, struct tcf_ematch *em,
4928c2ecf20Sopenharmony_ci			       struct tcf_pkt_info *info)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	int r = em->ops->match(skb, em, info);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	return tcf_em_is_inverted(em) ? !r : r;
4978c2ecf20Sopenharmony_ci}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci/* Do not use this function directly, use tcf_em_tree_match instead */
5008c2ecf20Sopenharmony_ciint __tcf_em_tree_match(struct sk_buff *skb, struct tcf_ematch_tree *tree,
5018c2ecf20Sopenharmony_ci			struct tcf_pkt_info *info)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	int stackp = 0, match_idx = 0, res = 0;
5048c2ecf20Sopenharmony_ci	struct tcf_ematch *cur_match;
5058c2ecf20Sopenharmony_ci	int stack[CONFIG_NET_EMATCH_STACK];
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ciproceed:
5088c2ecf20Sopenharmony_ci	while (match_idx < tree->hdr.nmatches) {
5098c2ecf20Sopenharmony_ci		cur_match = tcf_em_get_match(tree, match_idx);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci		if (tcf_em_is_container(cur_match)) {
5128c2ecf20Sopenharmony_ci			if (unlikely(stackp >= CONFIG_NET_EMATCH_STACK))
5138c2ecf20Sopenharmony_ci				goto stack_overflow;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci			stack[stackp++] = match_idx;
5168c2ecf20Sopenharmony_ci			match_idx = cur_match->data;
5178c2ecf20Sopenharmony_ci			goto proceed;
5188c2ecf20Sopenharmony_ci		}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci		res = tcf_em_match(skb, cur_match, info);
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci		if (tcf_em_early_end(cur_match, res))
5238c2ecf20Sopenharmony_ci			break;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci		match_idx++;
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cipop_stack:
5298c2ecf20Sopenharmony_ci	if (stackp > 0) {
5308c2ecf20Sopenharmony_ci		match_idx = stack[--stackp];
5318c2ecf20Sopenharmony_ci		cur_match = tcf_em_get_match(tree, match_idx);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci		if (tcf_em_is_inverted(cur_match))
5348c2ecf20Sopenharmony_ci			res = !res;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci		if (tcf_em_early_end(cur_match, res)) {
5378c2ecf20Sopenharmony_ci			goto pop_stack;
5388c2ecf20Sopenharmony_ci		} else {
5398c2ecf20Sopenharmony_ci			match_idx++;
5408c2ecf20Sopenharmony_ci			goto proceed;
5418c2ecf20Sopenharmony_ci		}
5428c2ecf20Sopenharmony_ci	}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	return res;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_cistack_overflow:
5478c2ecf20Sopenharmony_ci	net_warn_ratelimited("tc ematch: local stack overflow, increase NET_EMATCH_STACK\n");
5488c2ecf20Sopenharmony_ci	return -1;
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__tcf_em_tree_match);
551