Linux Audio

Check our new training course

Loading...
v4.10.11
 
  1/*
  2 * This program is free software; you can redistribute it and/or modify
  3 * it under the terms of the GNU General Public License version 2 as
  4 * published by the Free Software Foundation.
  5 *
  6 * Generic part shared by ipv4 and ipv6 backends.
  7 */
  8
  9#include <linux/kernel.h>
 10#include <linux/init.h>
 11#include <linux/module.h>
 12#include <linux/netlink.h>
 13#include <linux/netfilter.h>
 14#include <linux/netfilter/nf_tables.h>
 15#include <net/netfilter/nf_tables_core.h>
 16#include <net/netfilter/nf_tables.h>
 17#include <net/netfilter/nft_fib.h>
 18
 19const struct nla_policy nft_fib_policy[NFTA_FIB_MAX + 1] = {
 20	[NFTA_FIB_DREG]		= { .type = NLA_U32 },
 21	[NFTA_FIB_RESULT]	= { .type = NLA_U32 },
 22	[NFTA_FIB_FLAGS]	= { .type = NLA_U32 },
 23};
 24EXPORT_SYMBOL(nft_fib_policy);
 25
 26#define NFTA_FIB_F_ALL (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR | \
 27			NFTA_FIB_F_MARK | NFTA_FIB_F_IIF | NFTA_FIB_F_OIF)
 
 28
 29int nft_fib_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
 30		     const struct nft_data **data)
 31{
 32	const struct nft_fib *priv = nft_expr_priv(expr);
 33	unsigned int hooks;
 34
 35	switch (priv->result) {
 36	case NFT_FIB_RESULT_OIF: /* fallthrough */
 37	case NFT_FIB_RESULT_OIFNAME:
 38		hooks = (1 << NF_INET_PRE_ROUTING);
 
 
 
 
 39		break;
 40	case NFT_FIB_RESULT_ADDRTYPE:
 41		if (priv->flags & NFTA_FIB_F_IIF)
 42			hooks = (1 << NF_INET_PRE_ROUTING) |
 43				(1 << NF_INET_LOCAL_IN) |
 44				(1 << NF_INET_FORWARD);
 45		else if (priv->flags & NFTA_FIB_F_OIF)
 46			hooks = (1 << NF_INET_LOCAL_OUT) |
 47				(1 << NF_INET_POST_ROUTING) |
 48				(1 << NF_INET_FORWARD);
 49		else
 50			hooks = (1 << NF_INET_LOCAL_IN) |
 51				(1 << NF_INET_LOCAL_OUT) |
 52				(1 << NF_INET_FORWARD) |
 53				(1 << NF_INET_PRE_ROUTING) |
 54				(1 << NF_INET_POST_ROUTING);
 55
 56		break;
 57	default:
 58		return -EINVAL;
 59	}
 60
 61	return nft_chain_validate_hooks(ctx->chain, hooks);
 62}
 63EXPORT_SYMBOL_GPL(nft_fib_validate);
 64
 65int nft_fib_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
 66		 const struct nlattr * const tb[])
 67{
 68	struct nft_fib *priv = nft_expr_priv(expr);
 69	unsigned int len;
 70	int err;
 71
 72	if (!tb[NFTA_FIB_DREG] || !tb[NFTA_FIB_RESULT] || !tb[NFTA_FIB_FLAGS])
 73		return -EINVAL;
 74
 75	priv->flags = ntohl(nla_get_be32(tb[NFTA_FIB_FLAGS]));
 76
 77	if (priv->flags == 0 || (priv->flags & ~NFTA_FIB_F_ALL))
 78		return -EINVAL;
 79
 80	if ((priv->flags & (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR)) ==
 81			   (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR))
 82		return -EINVAL;
 83	if ((priv->flags & (NFTA_FIB_F_IIF | NFTA_FIB_F_OIF)) ==
 84			   (NFTA_FIB_F_IIF | NFTA_FIB_F_OIF))
 85		return -EINVAL;
 86	if ((priv->flags & (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR)) == 0)
 87		return -EINVAL;
 88
 89	priv->result = ntohl(nla_get_be32(tb[NFTA_FIB_RESULT]));
 90	priv->dreg = nft_parse_register(tb[NFTA_FIB_DREG]);
 91
 92	switch (priv->result) {
 93	case NFT_FIB_RESULT_OIF:
 94		if (priv->flags & NFTA_FIB_F_OIF)
 95			return -EINVAL;
 96		len = sizeof(int);
 97		break;
 98	case NFT_FIB_RESULT_OIFNAME:
 99		if (priv->flags & NFTA_FIB_F_OIF)
100			return -EINVAL;
101		len = IFNAMSIZ;
102		break;
103	case NFT_FIB_RESULT_ADDRTYPE:
104		len = sizeof(u32);
105		break;
106	default:
107		return -EINVAL;
108	}
109
110	err = nft_validate_register_store(ctx, priv->dreg, NULL,
111					  NFT_DATA_VALUE, len);
112	if (err < 0)
113		return err;
114
115	return nft_fib_validate(ctx, expr, NULL);
116}
117EXPORT_SYMBOL_GPL(nft_fib_init);
118
119int nft_fib_dump(struct sk_buff *skb, const struct nft_expr *expr)
120{
121	const struct nft_fib *priv = nft_expr_priv(expr);
122
123	if (nft_dump_register(skb, NFTA_FIB_DREG, priv->dreg))
124		return -1;
125
126	if (nla_put_be32(skb, NFTA_FIB_RESULT, htonl(priv->result)))
127		return -1;
128
129	if (nla_put_be32(skb, NFTA_FIB_FLAGS, htonl(priv->flags)))
130		return -1;
131
132	return 0;
133}
134EXPORT_SYMBOL_GPL(nft_fib_dump);
135
136void nft_fib_store_result(void *reg, enum nft_fib_result r,
137			  const struct nft_pktinfo *pkt, int index)
138{
139	struct net_device *dev;
140	u32 *dreg = reg;
 
141
142	switch (r) {
143	case NFT_FIB_RESULT_OIF:
144		*dreg = index;
 
145		break;
146	case NFT_FIB_RESULT_OIFNAME:
147		dev = dev_get_by_index_rcu(nft_net(pkt), index);
148		strncpy(reg, dev ? dev->name : "", IFNAMSIZ);
 
 
149		break;
150	default:
151		WARN_ON_ONCE(1);
152		*dreg = 0;
153		break;
154	}
155}
156EXPORT_SYMBOL_GPL(nft_fib_store_result);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
158MODULE_LICENSE("GPL");
159MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
v6.2
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
 
 
 
  3 *
  4 * Generic part shared by ipv4 and ipv6 backends.
  5 */
  6
  7#include <linux/kernel.h>
  8#include <linux/init.h>
  9#include <linux/module.h>
 10#include <linux/netlink.h>
 11#include <linux/netfilter.h>
 12#include <linux/netfilter/nf_tables.h>
 13#include <net/netfilter/nf_tables_core.h>
 14#include <net/netfilter/nf_tables.h>
 15#include <net/netfilter/nft_fib.h>
 16
 17const struct nla_policy nft_fib_policy[NFTA_FIB_MAX + 1] = {
 18	[NFTA_FIB_DREG]		= { .type = NLA_U32 },
 19	[NFTA_FIB_RESULT]	= { .type = NLA_U32 },
 20	[NFTA_FIB_FLAGS]	= { .type = NLA_U32 },
 21};
 22EXPORT_SYMBOL(nft_fib_policy);
 23
 24#define NFTA_FIB_F_ALL (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR | \
 25			NFTA_FIB_F_MARK | NFTA_FIB_F_IIF | NFTA_FIB_F_OIF | \
 26			NFTA_FIB_F_PRESENT)
 27
 28int nft_fib_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
 29		     const struct nft_data **data)
 30{
 31	const struct nft_fib *priv = nft_expr_priv(expr);
 32	unsigned int hooks;
 33
 34	switch (priv->result) {
 35	case NFT_FIB_RESULT_OIF:
 36	case NFT_FIB_RESULT_OIFNAME:
 37		hooks = (1 << NF_INET_PRE_ROUTING);
 38		if (priv->flags & NFTA_FIB_F_IIF) {
 39			hooks |= (1 << NF_INET_LOCAL_IN) |
 40				 (1 << NF_INET_FORWARD);
 41		}
 42		break;
 43	case NFT_FIB_RESULT_ADDRTYPE:
 44		if (priv->flags & NFTA_FIB_F_IIF)
 45			hooks = (1 << NF_INET_PRE_ROUTING) |
 46				(1 << NF_INET_LOCAL_IN) |
 47				(1 << NF_INET_FORWARD);
 48		else if (priv->flags & NFTA_FIB_F_OIF)
 49			hooks = (1 << NF_INET_LOCAL_OUT) |
 50				(1 << NF_INET_POST_ROUTING) |
 51				(1 << NF_INET_FORWARD);
 52		else
 53			hooks = (1 << NF_INET_LOCAL_IN) |
 54				(1 << NF_INET_LOCAL_OUT) |
 55				(1 << NF_INET_FORWARD) |
 56				(1 << NF_INET_PRE_ROUTING) |
 57				(1 << NF_INET_POST_ROUTING);
 58
 59		break;
 60	default:
 61		return -EINVAL;
 62	}
 63
 64	return nft_chain_validate_hooks(ctx->chain, hooks);
 65}
 66EXPORT_SYMBOL_GPL(nft_fib_validate);
 67
 68int nft_fib_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
 69		 const struct nlattr * const tb[])
 70{
 71	struct nft_fib *priv = nft_expr_priv(expr);
 72	unsigned int len;
 73	int err;
 74
 75	if (!tb[NFTA_FIB_DREG] || !tb[NFTA_FIB_RESULT] || !tb[NFTA_FIB_FLAGS])
 76		return -EINVAL;
 77
 78	priv->flags = ntohl(nla_get_be32(tb[NFTA_FIB_FLAGS]));
 79
 80	if (priv->flags == 0 || (priv->flags & ~NFTA_FIB_F_ALL))
 81		return -EINVAL;
 82
 83	if ((priv->flags & (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR)) ==
 84			   (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR))
 85		return -EINVAL;
 86	if ((priv->flags & (NFTA_FIB_F_IIF | NFTA_FIB_F_OIF)) ==
 87			   (NFTA_FIB_F_IIF | NFTA_FIB_F_OIF))
 88		return -EINVAL;
 89	if ((priv->flags & (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR)) == 0)
 90		return -EINVAL;
 91
 92	priv->result = ntohl(nla_get_be32(tb[NFTA_FIB_RESULT]));
 
 93
 94	switch (priv->result) {
 95	case NFT_FIB_RESULT_OIF:
 96		if (priv->flags & NFTA_FIB_F_OIF)
 97			return -EINVAL;
 98		len = sizeof(int);
 99		break;
100	case NFT_FIB_RESULT_OIFNAME:
101		if (priv->flags & NFTA_FIB_F_OIF)
102			return -EINVAL;
103		len = IFNAMSIZ;
104		break;
105	case NFT_FIB_RESULT_ADDRTYPE:
106		len = sizeof(u32);
107		break;
108	default:
109		return -EINVAL;
110	}
111
112	err = nft_parse_register_store(ctx, tb[NFTA_FIB_DREG], &priv->dreg,
113				       NULL, NFT_DATA_VALUE, len);
114	if (err < 0)
115		return err;
116
117	return 0;
118}
119EXPORT_SYMBOL_GPL(nft_fib_init);
120
121int nft_fib_dump(struct sk_buff *skb, const struct nft_expr *expr, bool reset)
122{
123	const struct nft_fib *priv = nft_expr_priv(expr);
124
125	if (nft_dump_register(skb, NFTA_FIB_DREG, priv->dreg))
126		return -1;
127
128	if (nla_put_be32(skb, NFTA_FIB_RESULT, htonl(priv->result)))
129		return -1;
130
131	if (nla_put_be32(skb, NFTA_FIB_FLAGS, htonl(priv->flags)))
132		return -1;
133
134	return 0;
135}
136EXPORT_SYMBOL_GPL(nft_fib_dump);
137
138void nft_fib_store_result(void *reg, const struct nft_fib *priv,
139			  const struct net_device *dev)
140{
 
141	u32 *dreg = reg;
142	int index;
143
144	switch (priv->result) {
145	case NFT_FIB_RESULT_OIF:
146		index = dev ? dev->ifindex : 0;
147		*dreg = (priv->flags & NFTA_FIB_F_PRESENT) ? !!index : index;
148		break;
149	case NFT_FIB_RESULT_OIFNAME:
150		if (priv->flags & NFTA_FIB_F_PRESENT)
151			*dreg = !!dev;
152		else
153			strncpy(reg, dev ? dev->name : "", IFNAMSIZ);
154		break;
155	default:
156		WARN_ON_ONCE(1);
157		*dreg = 0;
158		break;
159	}
160}
161EXPORT_SYMBOL_GPL(nft_fib_store_result);
162
163bool nft_fib_reduce(struct nft_regs_track *track,
164		    const struct nft_expr *expr)
165{
166	const struct nft_fib *priv = nft_expr_priv(expr);
167	unsigned int len = NFT_REG32_SIZE;
168	const struct nft_fib *fib;
169
170	switch (priv->result) {
171	case NFT_FIB_RESULT_OIF:
172		break;
173	case NFT_FIB_RESULT_OIFNAME:
174		if (priv->flags & NFTA_FIB_F_PRESENT)
175			len = NFT_REG32_SIZE;
176		else
177			len = IFNAMSIZ;
178		break;
179	case NFT_FIB_RESULT_ADDRTYPE:
180	     break;
181	default:
182		WARN_ON_ONCE(1);
183		break;
184	}
185
186	if (!nft_reg_track_cmp(track, expr, priv->dreg)) {
187		nft_reg_track_update(track, expr, priv->dreg, len);
188		return false;
189	}
190
191	fib = nft_expr_priv(track->regs[priv->dreg].selector);
192	if (priv->result != fib->result ||
193	    priv->flags != fib->flags) {
194		nft_reg_track_update(track, expr, priv->dreg, len);
195		return false;
196	}
197
198	if (!track->regs[priv->dreg].bitwise)
199		return true;
200
201	return false;
202}
203EXPORT_SYMBOL_GPL(nft_fib_reduce);
204
205MODULE_LICENSE("GPL");
206MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");