Blame view
net/netfilter/nf_sockopt.c
3.86 KB
f6ebe77f9 [NETFILTER]: spli... |
1 2 3 4 5 |
#include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> #include <linux/skbuff.h> #include <linux/netfilter.h> |
4a3e2f711 [NET] sem2mutex: ... |
6 |
#include <linux/mutex.h> |
f6ebe77f9 [NETFILTER]: spli... |
7 8 9 10 11 12 13 |
#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: ... |
14 |
static DEFINE_MUTEX(nf_sockopt_mutex); |
f6ebe77f9 [NETFILTER]: spli... |
15 16 17 18 19 20 21 22 23 24 25 |
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... |
26 |
struct nf_sockopt_ops *ops; |
f6ebe77f9 [NETFILTER]: spli... |
27 |
int ret = 0; |
4a3e2f711 [NET] sem2mutex: ... |
28 |
if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) |
f6ebe77f9 [NETFILTER]: spli... |
29 |
return -EINTR; |
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 36 37 |
reg->get_optmin, reg->get_optmax))) { NFDEBUG("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 |
|
4a3e2f711 [NET] sem2mutex: ... |
66 |
if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) |
4ce5ba6ae [NETFILTER]: Cons... |
67 |
return ERR_PTR(-EINTR); |
f6ebe77f9 [NETFILTER]: spli... |
68 |
|
55d84acd3 [NETFILTER]: nf_s... |
69 |
list_for_each_entry(ops, &nf_sockopts, list) { |
f6ebe77f9 [NETFILTER]: spli... |
70 |
if (ops->pf == pf) { |
16fcec35e [NETFILTER]: Fix/... |
71 72 |
if (!try_module_get(ops->owner)) goto out_nosup; |
4ce5ba6ae [NETFILTER]: Cons... |
73 |
|
f6ebe77f9 [NETFILTER]: spli... |
74 |
if (get) { |
4ce5ba6ae [NETFILTER]: Cons... |
75 76 |
if (val >= ops->get_optmin && val < ops->get_optmax) |
f6ebe77f9 [NETFILTER]: spli... |
77 |
goto out; |
f6ebe77f9 [NETFILTER]: spli... |
78 |
} else { |
4ce5ba6ae [NETFILTER]: Cons... |
79 80 |
if (val >= ops->set_optmin && val < ops->set_optmax) |
f6ebe77f9 [NETFILTER]: spli... |
81 |
goto out; |
f6ebe77f9 [NETFILTER]: spli... |
82 |
} |
16fcec35e [NETFILTER]: Fix/... |
83 |
module_put(ops->owner); |
f6ebe77f9 [NETFILTER]: spli... |
84 85 |
} } |
4ce5ba6ae [NETFILTER]: Cons... |
86 87 88 |
out_nosup: ops = ERR_PTR(-ENOPROTOOPT); out: |
4a3e2f711 [NET] sem2mutex: ... |
89 |
mutex_unlock(&nf_sockopt_mutex); |
4ce5ba6ae [NETFILTER]: Cons... |
90 91 92 93 |
return ops; } /* Call get/setsockopt() */ |
76108cea0 netfilter: Use un... |
94 |
static int nf_sockopt(struct sock *sk, u_int8_t pf, int val, |
4ce5ba6ae [NETFILTER]: Cons... |
95 96 97 98 99 100 101 102 103 104 105 106 107 |
char __user *opt, int *len, int get) { struct nf_sockopt_ops *ops; int ret; ops = nf_sockopt_find(sk, pf, val, get); if (IS_ERR(ops)) return PTR_ERR(ops); if (get) ret = ops->get(sk, val, opt, len); else ret = ops->set(sk, val, opt, *len); |
601e68e10 [NETFILTER]: Fix ... |
108 |
|
16fcec35e [NETFILTER]: Fix/... |
109 |
module_put(ops->owner); |
f6ebe77f9 [NETFILTER]: spli... |
110 111 |
return ret; } |
76108cea0 netfilter: Use un... |
112 |
int nf_setsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt, |
b7058842c net: Make setsock... |
113 |
unsigned int len) |
f6ebe77f9 [NETFILTER]: spli... |
114 115 116 117 |
{ return nf_sockopt(sk, pf, val, opt, &len, 0); } EXPORT_SYMBOL(nf_setsockopt); |
76108cea0 netfilter: Use un... |
118 119 |
int nf_getsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt, int *len) |
f6ebe77f9 [NETFILTER]: spli... |
120 121 122 123 |
{ return nf_sockopt(sk, pf, val, opt, len, 1); } EXPORT_SYMBOL(nf_getsockopt); |
3fdadf7d2 [NET]: {get|set}s... |
124 |
#ifdef CONFIG_COMPAT |
76108cea0 netfilter: Use un... |
125 |
static int compat_nf_sockopt(struct sock *sk, u_int8_t pf, int val, |
543d9cfee [NET]: Identation... |
126 |
char __user *opt, int *len, int get) |
3fdadf7d2 [NET]: {get|set}s... |
127 |
{ |
3fdadf7d2 [NET]: {get|set}s... |
128 129 |
struct nf_sockopt_ops *ops; int ret; |
4ce5ba6ae [NETFILTER]: Cons... |
130 131 132 133 134 135 136 137 |
ops = nf_sockopt_find(sk, pf, val, get); if (IS_ERR(ops)) return PTR_ERR(ops); if (get) { if (ops->compat_get) ret = ops->compat_get(sk, val, opt, len); else |
6452a5fde [NETFILTER]: fix ... |
138 |
ret = ops->get(sk, val, opt, len); |
4ce5ba6ae [NETFILTER]: Cons... |
139 140 |
} else { if (ops->compat_set) |
6452a5fde [NETFILTER]: fix ... |
141 |
ret = ops->compat_set(sk, val, opt, *len); |
4ce5ba6ae [NETFILTER]: Cons... |
142 |
else |
6452a5fde [NETFILTER]: fix ... |
143 |
ret = ops->set(sk, val, opt, *len); |
3fdadf7d2 [NET]: {get|set}s... |
144 |
} |
3fdadf7d2 [NET]: {get|set}s... |
145 |
|
16fcec35e [NETFILTER]: Fix/... |
146 |
module_put(ops->owner); |
3fdadf7d2 [NET]: {get|set}s... |
147 148 |
return ret; } |
76108cea0 netfilter: Use un... |
149 |
int compat_nf_setsockopt(struct sock *sk, u_int8_t pf, |
b7058842c net: Make setsock... |
150 |
int val, char __user *opt, unsigned int len) |
3fdadf7d2 [NET]: {get|set}s... |
151 152 153 154 |
{ return compat_nf_sockopt(sk, pf, val, opt, &len, 0); } EXPORT_SYMBOL(compat_nf_setsockopt); |
76108cea0 netfilter: Use un... |
155 |
int compat_nf_getsockopt(struct sock *sk, u_int8_t pf, |
3fdadf7d2 [NET]: {get|set}s... |
156 157 158 159 160 161 |
int val, char __user *opt, int *len) { return compat_nf_sockopt(sk, pf, val, opt, len, 1); } EXPORT_SYMBOL(compat_nf_getsockopt); #endif |