Blame view
net/netfilter/nf_sockopt.c
2.78 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
f6ebe77f9 [NETFILTER]: spli... |
2 3 4 5 6 |
#include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> #include <linux/skbuff.h> #include <linux/netfilter.h> |
4a3e2f711 [NET] sem2mutex: ... |
7 |
#include <linux/mutex.h> |
f6ebe77f9 [NETFILTER]: spli... |
8 9 10 11 12 13 14 |
#include <net/sock.h> #include "nf_internals.h" /* Sockopts only registered and called from user context, so net locking would be overkill. Also, [gs]etsockopt calls may sleep. */ |
4a3e2f711 [NET] sem2mutex: ... |
15 |
static DEFINE_MUTEX(nf_sockopt_mutex); |
f6ebe77f9 [NETFILTER]: spli... |
16 17 18 19 20 21 22 23 24 25 26 |
static LIST_HEAD(nf_sockopts); /* Do exclusive ranges overlap? */ static inline int overlap(int min1, int max1, int min2, int max2) { return max1 > min2 && min1 < max2; } /* Functions to register sockopt ranges (exclusive). */ int nf_register_sockopt(struct nf_sockopt_ops *reg) { |
55d84acd3 [NETFILTER]: nf_s... |
27 |
struct nf_sockopt_ops *ops; |
f6ebe77f9 [NETFILTER]: spli... |
28 |
int ret = 0; |
7926dbfa4 netfilter: don't ... |
29 |
mutex_lock(&nf_sockopt_mutex); |
55d84acd3 [NETFILTER]: nf_s... |
30 |
list_for_each_entry(ops, &nf_sockopts, list) { |
f6ebe77f9 [NETFILTER]: spli... |
31 |
if (ops->pf == reg->pf |
601e68e10 [NETFILTER]: Fix ... |
32 |
&& (overlap(ops->set_optmin, ops->set_optmax, |
f6ebe77f9 [NETFILTER]: spli... |
33 |
reg->set_optmin, reg->set_optmax) |
601e68e10 [NETFILTER]: Fix ... |
34 |
|| overlap(ops->get_optmin, ops->get_optmax, |
f6ebe77f9 [NETFILTER]: spli... |
35 |
reg->get_optmin, reg->get_optmax))) { |
b38cf9013 netfilter: Remove... |
36 37 |
pr_debug("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u ", |
601e68e10 [NETFILTER]: Fix ... |
38 39 |
ops->set_optmin, ops->set_optmax, ops->get_optmin, ops->get_optmax, |
f6ebe77f9 [NETFILTER]: spli... |
40 41 42 43 44 45 46 47 48 |
reg->set_optmin, reg->set_optmax, reg->get_optmin, reg->get_optmax); ret = -EBUSY; goto out; } } list_add(®->list, &nf_sockopts); out: |
4a3e2f711 [NET] sem2mutex: ... |
49 |
mutex_unlock(&nf_sockopt_mutex); |
f6ebe77f9 [NETFILTER]: spli... |
50 51 52 53 54 55 |
return ret; } EXPORT_SYMBOL(nf_register_sockopt); void nf_unregister_sockopt(struct nf_sockopt_ops *reg) { |
4a3e2f711 [NET] sem2mutex: ... |
56 |
mutex_lock(&nf_sockopt_mutex); |
f6ebe77f9 [NETFILTER]: spli... |
57 |
list_del(®->list); |
4a3e2f711 [NET] sem2mutex: ... |
58 |
mutex_unlock(&nf_sockopt_mutex); |
f6ebe77f9 [NETFILTER]: spli... |
59 60 |
} EXPORT_SYMBOL(nf_unregister_sockopt); |
76108cea0 netfilter: Use un... |
61 |
static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, u_int8_t pf, |
4ce5ba6ae [NETFILTER]: Cons... |
62 |
int val, int get) |
f6ebe77f9 [NETFILTER]: spli... |
63 |
{ |
f6ebe77f9 [NETFILTER]: spli... |
64 |
struct nf_sockopt_ops *ops; |
f6ebe77f9 [NETFILTER]: spli... |
65 |
|
7926dbfa4 netfilter: don't ... |
66 |
mutex_lock(&nf_sockopt_mutex); |
55d84acd3 [NETFILTER]: nf_s... |
67 |
list_for_each_entry(ops, &nf_sockopts, list) { |
f6ebe77f9 [NETFILTER]: spli... |
68 |
if (ops->pf == pf) { |
16fcec35e [NETFILTER]: Fix/... |
69 70 |
if (!try_module_get(ops->owner)) goto out_nosup; |
4ce5ba6ae [NETFILTER]: Cons... |
71 |
|
f6ebe77f9 [NETFILTER]: spli... |
72 |
if (get) { |
4ce5ba6ae [NETFILTER]: Cons... |
73 74 |
if (val >= ops->get_optmin && val < ops->get_optmax) |
f6ebe77f9 [NETFILTER]: spli... |
75 |
goto out; |
f6ebe77f9 [NETFILTER]: spli... |
76 |
} else { |
4ce5ba6ae [NETFILTER]: Cons... |
77 78 |
if (val >= ops->set_optmin && val < ops->set_optmax) |
f6ebe77f9 [NETFILTER]: spli... |
79 |
goto out; |
f6ebe77f9 [NETFILTER]: spli... |
80 |
} |
16fcec35e [NETFILTER]: Fix/... |
81 |
module_put(ops->owner); |
f6ebe77f9 [NETFILTER]: spli... |
82 83 |
} } |
4ce5ba6ae [NETFILTER]: Cons... |
84 85 86 |
out_nosup: ops = ERR_PTR(-ENOPROTOOPT); out: |
4a3e2f711 [NET] sem2mutex: ... |
87 |
mutex_unlock(&nf_sockopt_mutex); |
4ce5ba6ae [NETFILTER]: Cons... |
88 89 |
return ops; } |
c2f12630c netfilter: switch... |
90 |
int nf_setsockopt(struct sock *sk, u_int8_t pf, int val, sockptr_t opt, |
657e4c34a netfilter: split ... |
91 |
unsigned int len) |
4ce5ba6ae [NETFILTER]: Cons... |
92 93 94 |
{ struct nf_sockopt_ops *ops; int ret; |
657e4c34a netfilter: split ... |
95 |
ops = nf_sockopt_find(sk, pf, val, 0); |
4ce5ba6ae [NETFILTER]: Cons... |
96 97 |
if (IS_ERR(ops)) return PTR_ERR(ops); |
657e4c34a netfilter: split ... |
98 |
ret = ops->set(sk, val, opt, len); |
16fcec35e [NETFILTER]: Fix/... |
99 |
module_put(ops->owner); |
f6ebe77f9 [NETFILTER]: spli... |
100 101 |
return ret; } |
f6ebe77f9 [NETFILTER]: spli... |
102 |
EXPORT_SYMBOL(nf_setsockopt); |
76108cea0 netfilter: Use un... |
103 104 |
int nf_getsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt, int *len) |
f6ebe77f9 [NETFILTER]: spli... |
105 |
{ |
657e4c34a netfilter: split ... |
106 107 108 109 110 111 112 113 114 |
struct nf_sockopt_ops *ops; int ret; ops = nf_sockopt_find(sk, pf, val, 1); if (IS_ERR(ops)) return PTR_ERR(ops); ret = ops->get(sk, val, opt, len); module_put(ops->owner); return ret; |
f6ebe77f9 [NETFILTER]: spli... |
115 116 |
} EXPORT_SYMBOL(nf_getsockopt); |