2005-04-17 02:20:36 +04:00
|
|
|
/*
|
|
|
|
* Linux Socket Filter Data Structures
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __LINUX_FILTER_H__
|
|
|
|
#define __LINUX_FILTER_H__
|
|
|
|
|
|
|
|
#include <linux/compiler.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
|
|
|
|
#ifdef __KERNEL__
|
2011-07-27 03:09:06 +04:00
|
|
|
#include <linux/atomic.h>
|
2012-04-13 01:47:53 +04:00
|
|
|
#include <linux/compat.h>
|
2005-04-17 02:20:36 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Current version of the filter code architecture.
|
|
|
|
*/
|
|
|
|
#define BPF_MAJOR_VERSION 1
|
|
|
|
#define BPF_MINOR_VERSION 1
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Try and keep these values and structures similar to BSD, especially
|
|
|
|
* the BPF code definitions which need to match so you can share filters
|
|
|
|
*/
|
|
|
|
|
2009-11-04 20:50:58 +03:00
|
|
|
struct sock_filter { /* Filter block */
|
2006-09-01 02:28:39 +04:00
|
|
|
__u16 code; /* Actual filter code */
|
|
|
|
__u8 jt; /* Jump true */
|
|
|
|
__u8 jf; /* Jump false */
|
|
|
|
__u32 k; /* Generic multiuse field */
|
2005-04-17 02:20:36 +04:00
|
|
|
};
|
|
|
|
|
2009-11-04 20:50:58 +03:00
|
|
|
struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
|
2005-04-17 02:20:36 +04:00
|
|
|
unsigned short len; /* Number of filter blocks */
|
|
|
|
struct sock_filter __user *filter;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Instruction classes
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define BPF_CLASS(code) ((code) & 0x07)
|
|
|
|
#define BPF_LD 0x00
|
|
|
|
#define BPF_LDX 0x01
|
|
|
|
#define BPF_ST 0x02
|
|
|
|
#define BPF_STX 0x03
|
|
|
|
#define BPF_ALU 0x04
|
|
|
|
#define BPF_JMP 0x05
|
|
|
|
#define BPF_RET 0x06
|
|
|
|
#define BPF_MISC 0x07
|
|
|
|
|
|
|
|
/* ld/ldx fields */
|
|
|
|
#define BPF_SIZE(code) ((code) & 0x18)
|
|
|
|
#define BPF_W 0x00
|
|
|
|
#define BPF_H 0x08
|
|
|
|
#define BPF_B 0x10
|
|
|
|
#define BPF_MODE(code) ((code) & 0xe0)
|
|
|
|
#define BPF_IMM 0x00
|
|
|
|
#define BPF_ABS 0x20
|
|
|
|
#define BPF_IND 0x40
|
|
|
|
#define BPF_MEM 0x60
|
|
|
|
#define BPF_LEN 0x80
|
|
|
|
#define BPF_MSH 0xa0
|
|
|
|
|
|
|
|
/* alu/jmp fields */
|
|
|
|
#define BPF_OP(code) ((code) & 0xf0)
|
|
|
|
#define BPF_ADD 0x00
|
|
|
|
#define BPF_SUB 0x10
|
|
|
|
#define BPF_MUL 0x20
|
|
|
|
#define BPF_DIV 0x30
|
|
|
|
#define BPF_OR 0x40
|
|
|
|
#define BPF_AND 0x50
|
|
|
|
#define BPF_LSH 0x60
|
|
|
|
#define BPF_RSH 0x70
|
|
|
|
#define BPF_NEG 0x80
|
|
|
|
#define BPF_JA 0x00
|
|
|
|
#define BPF_JEQ 0x10
|
|
|
|
#define BPF_JGT 0x20
|
|
|
|
#define BPF_JGE 0x30
|
|
|
|
#define BPF_JSET 0x40
|
|
|
|
#define BPF_SRC(code) ((code) & 0x08)
|
|
|
|
#define BPF_K 0x00
|
|
|
|
#define BPF_X 0x08
|
|
|
|
|
|
|
|
/* ret - BPF_K and BPF_X also apply */
|
|
|
|
#define BPF_RVAL(code) ((code) & 0x18)
|
|
|
|
#define BPF_A 0x10
|
|
|
|
|
|
|
|
/* misc */
|
|
|
|
#define BPF_MISCOP(code) ((code) & 0xf8)
|
|
|
|
#define BPF_TAX 0x00
|
|
|
|
#define BPF_TXA 0x80
|
|
|
|
|
|
|
|
#ifndef BPF_MAXINSNS
|
|
|
|
#define BPF_MAXINSNS 4096
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Macros for filter block array initializers.
|
|
|
|
*/
|
|
|
|
#ifndef BPF_STMT
|
|
|
|
#define BPF_STMT(code, k) { (unsigned short)(code), 0, 0, k }
|
|
|
|
#endif
|
|
|
|
#ifndef BPF_JUMP
|
|
|
|
#define BPF_JUMP(code, k, jt, jf) { (unsigned short)(code), jt, jf, k }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Number of scratch memory words for: BPF_ST and BPF_STX
|
|
|
|
*/
|
|
|
|
#define BPF_MEMWORDS 16
|
|
|
|
|
|
|
|
/* RATIONALE. Negative offsets are invalid in BPF.
|
|
|
|
We use them to reference ancillary data.
|
|
|
|
Unlike introduction new instructions, it does not break
|
|
|
|
existing compilers/optimizers.
|
|
|
|
*/
|
|
|
|
#define SKF_AD_OFF (-0x1000)
|
|
|
|
#define SKF_AD_PROTOCOL 0
|
|
|
|
#define SKF_AD_PKTTYPE 4
|
|
|
|
#define SKF_AD_IFINDEX 8
|
[SKFILTER]: Add SKF_ADF_NLATTR instruction
SKF_ADF_NLATTR searches for a netlink attribute, which avoids manually
parsing and walking attributes. It takes the offset at which to start
searching in the 'A' register and the attribute type in the 'X' register
and returns the offset in the 'A' register. When the attribute is not
found it returns zero.
A top-level attribute can be located using a filter like this
(example for nfnetlink, using struct nfgenmsg):
...
{
/* A = offset of first attribute */
.code = BPF_LD | BPF_IMM,
.k = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg)
},
{
/* X = CTA_PROTOINFO */
.code = BPF_LDX | BPF_IMM,
.k = CTA_PROTOINFO,
},
{
/* A = netlink attribute offset */
.code = BPF_LD | BPF_B | BPF_ABS,
.k = SKF_AD_OFF + SKF_AD_NLATTR
},
{
/* Exit if not found */
.code = BPF_JMP | BPF_JEQ | BPF_K,
.k = 0,
.jt = <error>
},
...
A nested attribute below the CTA_PROTOINFO attribute would then
be parsed like this:
...
{
/* A += sizeof(struct nlattr) */
.code = BPF_ALU | BPF_ADD | BPF_K,
.k = sizeof(struct nlattr),
},
{
/* X = CTA_PROTOINFO_TCP */
.code = BPF_LDX | BPF_IMM,
.k = CTA_PROTOINFO_TCP,
},
{
/* A = netlink attribute offset */
.code = BPF_LD | BPF_B | BPF_ABS,
.k = SKF_AD_OFF + SKF_AD_NLATTR
},
...
The data of an attribute can be loaded into 'A' like this:
...
{
/* X = A (attribute offset) */
.code = BPF_MISC | BPF_TAX,
},
{
/* A = skb->data[X + k] */
.code = BPF_LD | BPF_B | BPF_IND,
.k = sizeof(struct nlattr),
},
...
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-04-10 13:02:28 +04:00
|
|
|
#define SKF_AD_NLATTR 12
|
2008-11-20 11:49:27 +03:00
|
|
|
#define SKF_AD_NLATTR_NEST 16
|
2009-10-19 06:17:56 +04:00
|
|
|
#define SKF_AD_MARK 20
|
2009-10-20 12:06:22 +04:00
|
|
|
#define SKF_AD_QUEUE 24
|
2010-04-22 07:32:22 +04:00
|
|
|
#define SKF_AD_HATYPE 28
|
2010-12-01 00:45:56 +03:00
|
|
|
#define SKF_AD_RXHASH 32
|
|
|
|
#define SKF_AD_CPU 36
|
2012-03-31 15:01:20 +04:00
|
|
|
#define SKF_AD_ALU_XOR_X 40
|
|
|
|
#define SKF_AD_MAX 44
|
2005-04-17 02:20:36 +04:00
|
|
|
#define SKF_NET_OFF (-0x100000)
|
|
|
|
#define SKF_LL_OFF (-0x200000)
|
|
|
|
|
|
|
|
#ifdef __KERNEL__
|
2011-05-22 11:08:11 +04:00
|
|
|
|
2012-04-13 01:47:53 +04:00
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
|
/*
|
|
|
|
* A struct sock_filter is architecture independent.
|
|
|
|
*/
|
|
|
|
struct compat_sock_fprog {
|
|
|
|
u16 len;
|
|
|
|
compat_uptr_t filter; /* struct sock_filter * */
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2011-05-22 11:08:11 +04:00
|
|
|
struct sk_buff;
|
|
|
|
struct sock;
|
|
|
|
|
2008-04-10 12:33:47 +04:00
|
|
|
struct sk_filter
|
|
|
|
{
|
|
|
|
atomic_t refcnt;
|
|
|
|
unsigned int len; /* Number of filter blocks */
|
2011-04-20 13:27:32 +04:00
|
|
|
unsigned int (*bpf_func)(const struct sk_buff *skb,
|
|
|
|
const struct sock_filter *filter);
|
2008-04-10 12:33:47 +04:00
|
|
|
struct rcu_head rcu;
|
|
|
|
struct sock_filter insns[0];
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline unsigned int sk_filter_len(const struct sk_filter *fp)
|
|
|
|
{
|
|
|
|
return fp->len * sizeof(struct sock_filter) + sizeof(*fp);
|
|
|
|
}
|
|
|
|
|
2008-04-10 12:43:09 +04:00
|
|
|
extern int sk_filter(struct sock *sk, struct sk_buff *skb);
|
2010-12-06 23:50:09 +03:00
|
|
|
extern unsigned int sk_run_filter(const struct sk_buff *skb,
|
2010-11-19 20:49:59 +03:00
|
|
|
const struct sock_filter *filter);
|
2012-03-31 15:01:19 +04:00
|
|
|
extern int sk_unattached_filter_create(struct sk_filter **pfp,
|
|
|
|
struct sock_fprog *fprog);
|
|
|
|
extern void sk_unattached_filter_destroy(struct sk_filter *fp);
|
2005-04-17 02:20:36 +04:00
|
|
|
extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
|
2007-10-18 08:21:26 +04:00
|
|
|
extern int sk_detach_filter(struct sock *sk);
|
2011-10-18 01:04:20 +04:00
|
|
|
extern int sk_chk_filter(struct sock_filter *filter, unsigned int flen);
|
2011-04-20 13:27:32 +04:00
|
|
|
|
|
|
|
#ifdef CONFIG_BPF_JIT
|
|
|
|
extern void bpf_jit_compile(struct sk_filter *fp);
|
|
|
|
extern void bpf_jit_free(struct sk_filter *fp);
|
|
|
|
#define SK_RUN_FILTER(FILTER, SKB) (*FILTER->bpf_func)(SKB, FILTER->insns)
|
|
|
|
#else
|
|
|
|
static inline void bpf_jit_compile(struct sk_filter *fp)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
static inline void bpf_jit_free(struct sk_filter *fp)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#define SK_RUN_FILTER(FILTER, SKB) sk_run_filter(SKB, FILTER->insns)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
enum {
|
|
|
|
BPF_S_RET_K = 1,
|
|
|
|
BPF_S_RET_A,
|
|
|
|
BPF_S_ALU_ADD_K,
|
|
|
|
BPF_S_ALU_ADD_X,
|
|
|
|
BPF_S_ALU_SUB_K,
|
|
|
|
BPF_S_ALU_SUB_X,
|
|
|
|
BPF_S_ALU_MUL_K,
|
|
|
|
BPF_S_ALU_MUL_X,
|
|
|
|
BPF_S_ALU_DIV_X,
|
|
|
|
BPF_S_ALU_AND_K,
|
|
|
|
BPF_S_ALU_AND_X,
|
|
|
|
BPF_S_ALU_OR_K,
|
|
|
|
BPF_S_ALU_OR_X,
|
|
|
|
BPF_S_ALU_LSH_K,
|
|
|
|
BPF_S_ALU_LSH_X,
|
|
|
|
BPF_S_ALU_RSH_K,
|
|
|
|
BPF_S_ALU_RSH_X,
|
|
|
|
BPF_S_ALU_NEG,
|
|
|
|
BPF_S_LD_W_ABS,
|
|
|
|
BPF_S_LD_H_ABS,
|
|
|
|
BPF_S_LD_B_ABS,
|
|
|
|
BPF_S_LD_W_LEN,
|
|
|
|
BPF_S_LD_W_IND,
|
|
|
|
BPF_S_LD_H_IND,
|
|
|
|
BPF_S_LD_B_IND,
|
|
|
|
BPF_S_LD_IMM,
|
|
|
|
BPF_S_LDX_W_LEN,
|
|
|
|
BPF_S_LDX_B_MSH,
|
|
|
|
BPF_S_LDX_IMM,
|
|
|
|
BPF_S_MISC_TAX,
|
|
|
|
BPF_S_MISC_TXA,
|
|
|
|
BPF_S_ALU_DIV_K,
|
|
|
|
BPF_S_LD_MEM,
|
|
|
|
BPF_S_LDX_MEM,
|
|
|
|
BPF_S_ST,
|
|
|
|
BPF_S_STX,
|
|
|
|
BPF_S_JMP_JA,
|
|
|
|
BPF_S_JMP_JEQ_K,
|
|
|
|
BPF_S_JMP_JEQ_X,
|
|
|
|
BPF_S_JMP_JGE_K,
|
|
|
|
BPF_S_JMP_JGE_X,
|
|
|
|
BPF_S_JMP_JGT_K,
|
|
|
|
BPF_S_JMP_JGT_X,
|
|
|
|
BPF_S_JMP_JSET_K,
|
|
|
|
BPF_S_JMP_JSET_X,
|
|
|
|
/* Ancillary data */
|
|
|
|
BPF_S_ANC_PROTOCOL,
|
|
|
|
BPF_S_ANC_PKTTYPE,
|
|
|
|
BPF_S_ANC_IFINDEX,
|
|
|
|
BPF_S_ANC_NLATTR,
|
|
|
|
BPF_S_ANC_NLATTR_NEST,
|
|
|
|
BPF_S_ANC_MARK,
|
|
|
|
BPF_S_ANC_QUEUE,
|
|
|
|
BPF_S_ANC_HATYPE,
|
|
|
|
BPF_S_ANC_RXHASH,
|
|
|
|
BPF_S_ANC_CPU,
|
2012-03-31 15:01:20 +04:00
|
|
|
BPF_S_ANC_ALU_XOR_X,
|
2012-04-13 01:47:52 +04:00
|
|
|
BPF_S_ANC_SECCOMP_LD_W,
|
2011-04-20 13:27:32 +04:00
|
|
|
};
|
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
#endif /* __KERNEL__ */
|
|
|
|
|
|
|
|
#endif /* __LINUX_FILTER_H__ */
|