diff options
author | Jiri Pirko <jpirko@redhat.com> | 2012-03-31 11:01:19 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-04-03 18:36:20 -0400 |
commit | 302d663740cfaf2c364df6bb61cd339014ed714c (patch) | |
tree | 85e3ea387a72e08b91b325850af062f430ce1260 | |
parent | fca231b2771cfd4e4f89445cf5c8dd81409b5b3c (diff) | |
download | linux-302d663740cfaf2c364df6bb61cd339014ed714c.tar.gz linux-302d663740cfaf2c364df6bb61cd339014ed714c.tar.bz2 linux-302d663740cfaf2c364df6bb61cd339014ed714c.zip |
filter: Allow to create sk-unattached filters
Today, BPF filters are bind to sockets. Since BPF machine becomes handy
for other purposes, this patch allows to create unattached filter.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/filter.h | 3 | ||||
-rw-r--r-- | net/core/filter.c | 66 |
2 files changed, 65 insertions, 4 deletions
diff --git a/include/linux/filter.h b/include/linux/filter.h index 8eeb205f298b..92dd9933c43d 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -153,6 +153,9 @@ static inline unsigned int sk_filter_len(const struct sk_filter *fp) extern int sk_filter(struct sock *sk, struct sk_buff *skb); extern unsigned int sk_run_filter(const struct sk_buff *skb, const struct sock_filter *filter); +extern int sk_unattached_filter_create(struct sk_filter **pfp, + struct sock_fprog *fprog); +extern void sk_unattached_filter_destroy(struct sk_filter *fp); extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); extern int sk_detach_filter(struct sock *sk); extern int sk_chk_filter(struct sock_filter *filter, unsigned int flen); diff --git a/net/core/filter.c b/net/core/filter.c index 5dea45279215..cfbea889a0eb 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -587,6 +587,67 @@ void sk_filter_release_rcu(struct rcu_head *rcu) } EXPORT_SYMBOL(sk_filter_release_rcu); +static int __sk_prepare_filter(struct sk_filter *fp) +{ + int err; + + fp->bpf_func = sk_run_filter; + + err = sk_chk_filter(fp->insns, fp->len); + if (err) + return err; + + bpf_jit_compile(fp); + return 0; +} + +/** + * sk_unattached_filter_create - create an unattached filter + * @fprog: the filter program + * @sk: the socket to use + * + * Create a filter independent ofr any socket. We first run some + * sanity checks on it to make sure it does not explode on us later. + * If an error occurs or there is insufficient memory for the filter + * a negative errno code is returned. On success the return is zero. + */ +int sk_unattached_filter_create(struct sk_filter **pfp, + struct sock_fprog *fprog) +{ + struct sk_filter *fp; + unsigned int fsize = sizeof(struct sock_filter) * fprog->len; + int err; + + /* Make sure new filter is there and in the right amounts. */ + if (fprog->filter == NULL) + return -EINVAL; + + fp = kmalloc(fsize + sizeof(*fp), GFP_KERNEL); + if (!fp) + return -ENOMEM; + memcpy(fp->insns, fprog->filter, fsize); + + atomic_set(&fp->refcnt, 1); + fp->len = fprog->len; + + err = __sk_prepare_filter(fp); + if (err) + goto free_mem; + + *pfp = fp; + return 0; +free_mem: + kfree(fp); + return err; +} +EXPORT_SYMBOL_GPL(sk_unattached_filter_create); + +void sk_unattached_filter_destroy(struct sk_filter *fp) +{ + sk_filter_release(fp); +} +EXPORT_SYMBOL_GPL(sk_unattached_filter_destroy); + /** * sk_attach_filter - attach a socket filter * @fprog: the filter program @@ -617,16 +678,13 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) atomic_set(&fp->refcnt, 1); fp->len = fprog->len; - fp->bpf_func = sk_run_filter; - err = sk_chk_filter(fp->insns, fp->len); + err = __sk_prepare_filter(fp); if (err) { sk_filter_uncharge(sk, fp); return err; } - bpf_jit_compile(fp); - old_fp = rcu_dereference_protected(sk->sk_filter, sock_owned_by_user(sk)); rcu_assign_pointer(sk->sk_filter, fp); |