diff options
author | Harald Welte <laforge@netfilter.org> | 2005-08-09 23:21:49 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-08-29 18:51:11 -0400 |
commit | f6ebe77f955d77a988ce726f0818ec0103b11323 (patch) | |
tree | 8fefa0e00c4214c3d8ba06c5122c5977b3a9391a /net/netfilter/nf_sockopt.c | |
parent | 210a9ebef2d1bd32d9e9d81c84d538e237769cdb (diff) |
[NETFILTER]: split net/core/netfilter.c into net/netfilter/*.c
This patch doesn't introduce any code changes, but merely splits the
core netfilter code into four separate files. It also moves it from
it's old location in net/core/ to the recently-created net/netfilter/
directory.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netfilter/nf_sockopt.c')
-rw-r--r-- | net/netfilter/nf_sockopt.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c new file mode 100644 index 00000000000..61a833a9caa --- /dev/null +++ b/net/netfilter/nf_sockopt.c | |||
@@ -0,0 +1,132 @@ | |||
1 | #include <linux/config.h> | ||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/init.h> | ||
4 | #include <linux/module.h> | ||
5 | #include <linux/skbuff.h> | ||
6 | #include <linux/netfilter.h> | ||
7 | #include <net/sock.h> | ||
8 | |||
9 | #include "nf_internals.h" | ||
10 | |||
11 | /* Sockopts only registered and called from user context, so | ||
12 | net locking would be overkill. Also, [gs]etsockopt calls may | ||
13 | sleep. */ | ||
14 | static DECLARE_MUTEX(nf_sockopt_mutex); | ||
15 | static LIST_HEAD(nf_sockopts); | ||
16 | |||
17 | /* Do exclusive ranges overlap? */ | ||
18 | static inline int overlap(int min1, int max1, int min2, int max2) | ||
19 | { | ||
20 | return max1 > min2 && min1 < max2; | ||
21 | } | ||
22 | |||
23 | /* Functions to register sockopt ranges (exclusive). */ | ||
24 | int nf_register_sockopt(struct nf_sockopt_ops *reg) | ||
25 | { | ||
26 | struct list_head *i; | ||
27 | int ret = 0; | ||
28 | |||
29 | if (down_interruptible(&nf_sockopt_mutex) != 0) | ||
30 | return -EINTR; | ||
31 | |||
32 | list_for_each(i, &nf_sockopts) { | ||
33 | struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i; | ||
34 | if (ops->pf == reg->pf | ||
35 | && (overlap(ops->set_optmin, ops->set_optmax, | ||
36 | reg->set_optmin, reg->set_optmax) | ||
37 | || overlap(ops->get_optmin, ops->get_optmax, | ||
38 | reg->get_optmin, reg->get_optmax))) { | ||
39 | NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n", | ||
40 | ops->set_optmin, ops->set_optmax, | ||
41 | ops->get_optmin, ops->get_optmax, | ||
42 | reg->set_optmin, reg->set_optmax, | ||
43 | reg->get_optmin, reg->get_optmax); | ||
44 | ret = -EBUSY; | ||
45 | goto out; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | list_add(®->list, &nf_sockopts); | ||
50 | out: | ||
51 | up(&nf_sockopt_mutex); | ||
52 | return ret; | ||
53 | } | ||
54 | EXPORT_SYMBOL(nf_register_sockopt); | ||
55 | |||
56 | void nf_unregister_sockopt(struct nf_sockopt_ops *reg) | ||
57 | { | ||
58 | /* No point being interruptible: we're probably in cleanup_module() */ | ||
59 | restart: | ||
60 | down(&nf_sockopt_mutex); | ||
61 | if (reg->use != 0) { | ||
62 | /* To be woken by nf_sockopt call... */ | ||
63 | /* FIXME: Stuart Young's name appears gratuitously. */ | ||
64 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
65 | reg->cleanup_task = current; | ||
66 | up(&nf_sockopt_mutex); | ||
67 | schedule(); | ||
68 | goto restart; | ||
69 | } | ||
70 | list_del(®->list); | ||
71 | up(&nf_sockopt_mutex); | ||
72 | } | ||
73 | EXPORT_SYMBOL(nf_unregister_sockopt); | ||
74 | |||
75 | /* Call get/setsockopt() */ | ||
76 | static int nf_sockopt(struct sock *sk, int pf, int val, | ||
77 | char __user *opt, int *len, int get) | ||
78 | { | ||
79 | struct list_head *i; | ||
80 | struct nf_sockopt_ops *ops; | ||
81 | int ret; | ||
82 | |||
83 | if (down_interruptible(&nf_sockopt_mutex) != 0) | ||
84 | return -EINTR; | ||
85 | |||
86 | list_for_each(i, &nf_sockopts) { | ||
87 | ops = (struct nf_sockopt_ops *)i; | ||
88 | if (ops->pf == pf) { | ||
89 | if (get) { | ||
90 | if (val >= ops->get_optmin | ||
91 | && val < ops->get_optmax) { | ||
92 | ops->use++; | ||
93 | up(&nf_sockopt_mutex); | ||
94 | ret = ops->get(sk, val, opt, len); | ||
95 | goto out; | ||
96 | } | ||
97 | } else { | ||
98 | if (val >= ops->set_optmin | ||
99 | && val < ops->set_optmax) { | ||
100 | ops->use++; | ||
101 | up(&nf_sockopt_mutex); | ||
102 | ret = ops->set(sk, val, opt, *len); | ||
103 | goto out; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | up(&nf_sockopt_mutex); | ||
109 | return -ENOPROTOOPT; | ||
110 | |||
111 | out: | ||
112 | down(&nf_sockopt_mutex); | ||
113 | ops->use--; | ||
114 | if (ops->cleanup_task) | ||
115 | wake_up_process(ops->cleanup_task); | ||
116 | up(&nf_sockopt_mutex); | ||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | int nf_setsockopt(struct sock *sk, int pf, int val, char __user *opt, | ||
121 | int len) | ||
122 | { | ||
123 | return nf_sockopt(sk, pf, val, opt, &len, 0); | ||
124 | } | ||
125 | EXPORT_SYMBOL(nf_setsockopt); | ||
126 | |||
127 | int nf_getsockopt(struct sock *sk, int pf, int val, char __user *opt, int *len) | ||
128 | { | ||
129 | return nf_sockopt(sk, pf, val, opt, len, 1); | ||
130 | } | ||
131 | EXPORT_SYMBOL(nf_getsockopt); | ||
132 | |||