Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2012-2016 Pablo Neira Ayuso <pablo@netfilter.org>
  4 */
  5
  6#include <linux/init.h>
  7#include <linux/module.h>
  8#include <linux/skbuff.h>
  9#include <linux/netlink.h>
 10#include <linux/netfilter.h>
 11#include <linux/netfilter/nf_tables.h>
 12#include <net/netfilter/nf_tables_core.h>
 13
 14#define nft_objref_priv(expr)	*((struct nft_object **)nft_expr_priv(expr))
 15
 16static void nft_objref_eval(const struct nft_expr *expr,
 17			    struct nft_regs *regs,
 18			    const struct nft_pktinfo *pkt)
 19{
 20	struct nft_object *obj = nft_objref_priv(expr);
 21
 22	obj->ops->eval(obj, regs, pkt);
 23}
 24
 25static int nft_objref_init(const struct nft_ctx *ctx,
 26			   const struct nft_expr *expr,
 27			   const struct nlattr * const tb[])
 28{
 29	struct nft_object *obj = nft_objref_priv(expr);
 30	u8 genmask = nft_genmask_next(ctx->net);
 31	u32 objtype;
 32
 33	if (!tb[NFTA_OBJREF_IMM_NAME] ||
 34	    !tb[NFTA_OBJREF_IMM_TYPE])
 35		return -EINVAL;
 36
 37	objtype = ntohl(nla_get_be32(tb[NFTA_OBJREF_IMM_TYPE]));
 38	obj = nft_obj_lookup(ctx->net, ctx->table,
 39			     tb[NFTA_OBJREF_IMM_NAME], objtype,
 40			     genmask);
 41	if (IS_ERR(obj))
 42		return -ENOENT;
 43
 44	nft_objref_priv(expr) = obj;
 45	obj->use++;
 46
 47	return 0;
 48}
 49
 50static int nft_objref_dump(struct sk_buff *skb,
 51			   const struct nft_expr *expr, bool reset)
 52{
 53	const struct nft_object *obj = nft_objref_priv(expr);
 54
 55	if (nla_put_string(skb, NFTA_OBJREF_IMM_NAME, obj->key.name) ||
 56	    nla_put_be32(skb, NFTA_OBJREF_IMM_TYPE,
 57			 htonl(obj->ops->type->type)))
 58		goto nla_put_failure;
 59
 60	return 0;
 61
 62nla_put_failure:
 63	return -1;
 64}
 65
 66static void nft_objref_deactivate(const struct nft_ctx *ctx,
 67				  const struct nft_expr *expr,
 68				  enum nft_trans_phase phase)
 69{
 70	struct nft_object *obj = nft_objref_priv(expr);
 71
 72	if (phase == NFT_TRANS_COMMIT)
 73		return;
 74
 75	obj->use--;
 76}
 77
 78static void nft_objref_activate(const struct nft_ctx *ctx,
 79				const struct nft_expr *expr)
 80{
 81	struct nft_object *obj = nft_objref_priv(expr);
 82
 83	obj->use++;
 84}
 85
 86static const struct nft_expr_ops nft_objref_ops = {
 87	.type		= &nft_objref_type,
 88	.size		= NFT_EXPR_SIZE(sizeof(struct nft_object *)),
 89	.eval		= nft_objref_eval,
 90	.init		= nft_objref_init,
 91	.activate	= nft_objref_activate,
 92	.deactivate	= nft_objref_deactivate,
 93	.dump		= nft_objref_dump,
 94	.reduce		= NFT_REDUCE_READONLY,
 95};
 96
 97struct nft_objref_map {
 98	struct nft_set		*set;
 99	u8			sreg;
100	struct nft_set_binding	binding;
101};
102
103static void nft_objref_map_eval(const struct nft_expr *expr,
104				struct nft_regs *regs,
105				const struct nft_pktinfo *pkt)
106{
107	struct nft_objref_map *priv = nft_expr_priv(expr);
108	const struct nft_set *set = priv->set;
109	struct net *net = nft_net(pkt);
110	const struct nft_set_ext *ext;
111	struct nft_object *obj;
112	bool found;
113
114	found = nft_set_do_lookup(net, set, &regs->data[priv->sreg], &ext);
115	if (!found) {
116		ext = nft_set_catchall_lookup(net, set);
117		if (!ext) {
118			regs->verdict.code = NFT_BREAK;
119			return;
120		}
121	}
122	obj = *nft_set_ext_obj(ext);
123	obj->ops->eval(obj, regs, pkt);
124}
125
126static int nft_objref_map_init(const struct nft_ctx *ctx,
127			       const struct nft_expr *expr,
128			       const struct nlattr * const tb[])
129{
130	struct nft_objref_map *priv = nft_expr_priv(expr);
131	u8 genmask = nft_genmask_next(ctx->net);
132	struct nft_set *set;
133	int err;
134
135	set = nft_set_lookup_global(ctx->net, ctx->table,
136				    tb[NFTA_OBJREF_SET_NAME],
137				    tb[NFTA_OBJREF_SET_ID], genmask);
138	if (IS_ERR(set))
139		return PTR_ERR(set);
140
141	if (!(set->flags & NFT_SET_OBJECT))
142		return -EINVAL;
143
144	err = nft_parse_register_load(tb[NFTA_OBJREF_SET_SREG], &priv->sreg,
145				      set->klen);
146	if (err < 0)
147		return err;
148
149	priv->binding.flags = set->flags & NFT_SET_OBJECT;
150
151	err = nf_tables_bind_set(ctx, set, &priv->binding);
152	if (err < 0)
153		return err;
154
155	priv->set = set;
156	return 0;
157}
158
159static int nft_objref_map_dump(struct sk_buff *skb,
160			       const struct nft_expr *expr, bool reset)
161{
162	const struct nft_objref_map *priv = nft_expr_priv(expr);
163
164	if (nft_dump_register(skb, NFTA_OBJREF_SET_SREG, priv->sreg) ||
165	    nla_put_string(skb, NFTA_OBJREF_SET_NAME, priv->set->name))
166		goto nla_put_failure;
167
168	return 0;
169
170nla_put_failure:
171	return -1;
172}
173
174static void nft_objref_map_deactivate(const struct nft_ctx *ctx,
175				      const struct nft_expr *expr,
176				      enum nft_trans_phase phase)
177{
178	struct nft_objref_map *priv = nft_expr_priv(expr);
179
180	nf_tables_deactivate_set(ctx, priv->set, &priv->binding, phase);
181}
182
183static void nft_objref_map_activate(const struct nft_ctx *ctx,
184				    const struct nft_expr *expr)
185{
186	struct nft_objref_map *priv = nft_expr_priv(expr);
187
188	priv->set->use++;
189}
190
191static void nft_objref_map_destroy(const struct nft_ctx *ctx,
192				   const struct nft_expr *expr)
193{
194	struct nft_objref_map *priv = nft_expr_priv(expr);
195
196	nf_tables_destroy_set(ctx, priv->set);
197}
198
199static const struct nft_expr_ops nft_objref_map_ops = {
200	.type		= &nft_objref_type,
201	.size		= NFT_EXPR_SIZE(sizeof(struct nft_objref_map)),
202	.eval		= nft_objref_map_eval,
203	.init		= nft_objref_map_init,
204	.activate	= nft_objref_map_activate,
205	.deactivate	= nft_objref_map_deactivate,
206	.destroy	= nft_objref_map_destroy,
207	.dump		= nft_objref_map_dump,
208	.reduce		= NFT_REDUCE_READONLY,
209};
210
211static const struct nft_expr_ops *
212nft_objref_select_ops(const struct nft_ctx *ctx,
213                      const struct nlattr * const tb[])
214{
215	if (tb[NFTA_OBJREF_SET_SREG] &&
216	    (tb[NFTA_OBJREF_SET_NAME] ||
217	     tb[NFTA_OBJREF_SET_ID]))
218		return &nft_objref_map_ops;
219	else if (tb[NFTA_OBJREF_IMM_NAME] &&
220		 tb[NFTA_OBJREF_IMM_TYPE])
221		return &nft_objref_ops;
222
223	return ERR_PTR(-EOPNOTSUPP);
224}
225
226static const struct nla_policy nft_objref_policy[NFTA_OBJREF_MAX + 1] = {
227	[NFTA_OBJREF_IMM_NAME]	= { .type = NLA_STRING,
228				    .len = NFT_OBJ_MAXNAMELEN - 1 },
229	[NFTA_OBJREF_IMM_TYPE]	= { .type = NLA_U32 },
230	[NFTA_OBJREF_SET_SREG]	= { .type = NLA_U32 },
231	[NFTA_OBJREF_SET_NAME]	= { .type = NLA_STRING,
232				    .len = NFT_SET_MAXNAMELEN - 1 },
233	[NFTA_OBJREF_SET_ID]	= { .type = NLA_U32 },
234};
235
236struct nft_expr_type nft_objref_type __read_mostly = {
237	.name		= "objref",
238	.select_ops	= nft_objref_select_ops,
239	.policy		= nft_objref_policy,
240	.maxattr	= NFTA_OBJREF_MAX,
241	.owner		= THIS_MODULE,
242};