aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter.h28
-rw-r--r--net/netfilter/core.c32
-rw-r--r--net/netfilter/nf_internals.h11
-rw-r--r--net/netfilter/nf_queue.c38
4 files changed, 59 insertions, 50 deletions
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 2517ece98820..aee7ef1e23ed 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -44,6 +44,16 @@ int netfilter_init(void);
44struct sk_buff; 44struct sk_buff;
45 45
46struct nf_hook_ops; 46struct nf_hook_ops;
47
48struct nf_hook_state {
49 unsigned int hook;
50 int thresh;
51 u_int8_t pf;
52 struct net_device *in;
53 struct net_device *out;
54 int (*okfn)(struct sk_buff *);
55};
56
47typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops, 57typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops,
48 struct sk_buff *skb, 58 struct sk_buff *skb,
49 const struct net_device *in, 59 const struct net_device *in,
@@ -118,9 +128,7 @@ static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook)
118} 128}
119#endif 129#endif
120 130
121int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb, 131int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state);
122 struct net_device *indev, struct net_device *outdev,
123 int (*okfn)(struct sk_buff *), int thresh);
124 132
125/** 133/**
126 * nf_hook_thresh - call a netfilter hook 134 * nf_hook_thresh - call a netfilter hook
@@ -135,8 +143,18 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
135 struct net_device *outdev, 143 struct net_device *outdev,
136 int (*okfn)(struct sk_buff *), int thresh) 144 int (*okfn)(struct sk_buff *), int thresh)
137{ 145{
138 if (nf_hooks_active(pf, hook)) 146 if (nf_hooks_active(pf, hook)) {
139 return nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh); 147 struct nf_hook_state state = {
148 .hook = hook,
149 .thresh = thresh,
150 .pf = pf,
151 .in = indev,
152 .out = outdev,
153 .okfn = okfn
154 };
155
156 return nf_hook_slow(skb, &state);
157 }
140 return 1; 158 return 1;
141} 159}
142 160
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index fea9ef566427..11d04ebfc5e3 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -120,12 +120,8 @@ EXPORT_SYMBOL(nf_unregister_hooks);
120 120
121unsigned int nf_iterate(struct list_head *head, 121unsigned int nf_iterate(struct list_head *head,
122 struct sk_buff *skb, 122 struct sk_buff *skb,
123 unsigned int hook, 123 struct nf_hook_state *state,
124 const struct net_device *indev, 124 struct nf_hook_ops **elemp)
125 const struct net_device *outdev,
126 struct nf_hook_ops **elemp,
127 int (*okfn)(struct sk_buff *),
128 int hook_thresh)
129{ 125{
130 unsigned int verdict; 126 unsigned int verdict;
131 127
@@ -134,19 +130,20 @@ unsigned int nf_iterate(struct list_head *head,
134 * function because of risk of continuing from deleted element. 130 * function because of risk of continuing from deleted element.
135 */ 131 */
136 list_for_each_entry_continue_rcu((*elemp), head, list) { 132 list_for_each_entry_continue_rcu((*elemp), head, list) {
137 if (hook_thresh > (*elemp)->priority) 133 if (state->thresh > (*elemp)->priority)
138 continue; 134 continue;
139 135
140 /* Optimization: we don't need to hold module 136 /* Optimization: we don't need to hold module
141 reference here, since function can't sleep. --RR */ 137 reference here, since function can't sleep. --RR */
142repeat: 138repeat:
143 verdict = (*elemp)->hook(*elemp, skb, indev, outdev, okfn); 139 verdict = (*elemp)->hook(*elemp, skb, state->in, state->out,
140 state->okfn);
144 if (verdict != NF_ACCEPT) { 141 if (verdict != NF_ACCEPT) {
145#ifdef CONFIG_NETFILTER_DEBUG 142#ifdef CONFIG_NETFILTER_DEBUG
146 if (unlikely((verdict & NF_VERDICT_MASK) 143 if (unlikely((verdict & NF_VERDICT_MASK)
147 > NF_MAX_VERDICT)) { 144 > NF_MAX_VERDICT)) {
148 NFDEBUG("Evil return from %p(%u).\n", 145 NFDEBUG("Evil return from %p(%u).\n",
149 (*elemp)->hook, hook); 146 (*elemp)->hook, state->hook);
150 continue; 147 continue;
151 } 148 }
152#endif 149#endif
@@ -161,11 +158,7 @@ repeat:
161 158
162/* Returns 1 if okfn() needs to be executed by the caller, 159/* Returns 1 if okfn() needs to be executed by the caller,
163 * -EPERM for NF_DROP, 0 otherwise. */ 160 * -EPERM for NF_DROP, 0 otherwise. */
164int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb, 161int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state)
165 struct net_device *indev,
166 struct net_device *outdev,
167 int (*okfn)(struct sk_buff *),
168 int hook_thresh)
169{ 162{
170 struct nf_hook_ops *elem; 163 struct nf_hook_ops *elem;
171 unsigned int verdict; 164 unsigned int verdict;
@@ -174,10 +167,11 @@ int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
174 /* We may already have this, but read-locks nest anyway */ 167 /* We may already have this, but read-locks nest anyway */
175 rcu_read_lock(); 168 rcu_read_lock();
176 169
177 elem = list_entry_rcu(&nf_hooks[pf][hook], struct nf_hook_ops, list); 170 elem = list_entry_rcu(&nf_hooks[state->pf][state->hook],
171 struct nf_hook_ops, list);
178next_hook: 172next_hook:
179 verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev, 173 verdict = nf_iterate(&nf_hooks[state->pf][state->hook], skb, state,
180 outdev, &elem, okfn, hook_thresh); 174 &elem);
181 if (verdict == NF_ACCEPT || verdict == NF_STOP) { 175 if (verdict == NF_ACCEPT || verdict == NF_STOP) {
182 ret = 1; 176 ret = 1;
183 } else if ((verdict & NF_VERDICT_MASK) == NF_DROP) { 177 } else if ((verdict & NF_VERDICT_MASK) == NF_DROP) {
@@ -186,8 +180,8 @@ next_hook:
186 if (ret == 0) 180 if (ret == 0)
187 ret = -EPERM; 181 ret = -EPERM;
188 } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { 182 } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
189 int err = nf_queue(skb, elem, pf, hook, indev, outdev, okfn, 183 int err = nf_queue(skb, elem, state,
190 verdict >> NF_VERDICT_QBITS); 184 verdict >> NF_VERDICT_QBITS);
191 if (err < 0) { 185 if (err < 0) {
192 if (err == -ECANCELED) 186 if (err == -ECANCELED)
193 goto next_hook; 187 goto next_hook;
diff --git a/net/netfilter/nf_internals.h b/net/netfilter/nf_internals.h
index 61a3c927e63c..ea7f36784b3d 100644
--- a/net/netfilter/nf_internals.h
+++ b/net/netfilter/nf_internals.h
@@ -14,16 +14,11 @@
14 14
15/* core.c */ 15/* core.c */
16unsigned int nf_iterate(struct list_head *head, struct sk_buff *skb, 16unsigned int nf_iterate(struct list_head *head, struct sk_buff *skb,
17 unsigned int hook, const struct net_device *indev, 17 struct nf_hook_state *state, struct nf_hook_ops **elemp);
18 const struct net_device *outdev,
19 struct nf_hook_ops **elemp,
20 int (*okfn)(struct sk_buff *), int hook_thresh);
21 18
22/* nf_queue.c */ 19/* nf_queue.c */
23int nf_queue(struct sk_buff *skb, struct nf_hook_ops *elem, u_int8_t pf, 20int nf_queue(struct sk_buff *skb, struct nf_hook_ops *elem,
24 unsigned int hook, struct net_device *indev, 21 struct nf_hook_state *state, unsigned int queuenum);
25 struct net_device *outdev, int (*okfn)(struct sk_buff *),
26 unsigned int queuenum);
27int __init netfilter_queue_init(void); 22int __init netfilter_queue_init(void);
28 23
29/* nf_log.c */ 24/* nf_log.c */
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index 4c8b68e5fa16..6f8e9485cc83 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -100,12 +100,9 @@ EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs);
100 * through nf_reinject(). 100 * through nf_reinject().
101 */ 101 */
102int nf_queue(struct sk_buff *skb, 102int nf_queue(struct sk_buff *skb,
103 struct nf_hook_ops *elem, 103 struct nf_hook_ops *elem,
104 u_int8_t pf, unsigned int hook, 104 struct nf_hook_state *state,
105 struct net_device *indev, 105 unsigned int queuenum)
106 struct net_device *outdev,
107 int (*okfn)(struct sk_buff *),
108 unsigned int queuenum)
109{ 106{
110 int status = -ENOENT; 107 int status = -ENOENT;
111 struct nf_queue_entry *entry = NULL; 108 struct nf_queue_entry *entry = NULL;
@@ -121,7 +118,7 @@ int nf_queue(struct sk_buff *skb,
121 goto err_unlock; 118 goto err_unlock;
122 } 119 }
123 120
124 afinfo = nf_get_afinfo(pf); 121 afinfo = nf_get_afinfo(state->pf);
125 if (!afinfo) 122 if (!afinfo)
126 goto err_unlock; 123 goto err_unlock;
127 124
@@ -134,11 +131,11 @@ int nf_queue(struct sk_buff *skb,
134 *entry = (struct nf_queue_entry) { 131 *entry = (struct nf_queue_entry) {
135 .skb = skb, 132 .skb = skb,
136 .elem = elem, 133 .elem = elem,
137 .pf = pf, 134 .pf = state->pf,
138 .hook = hook, 135 .hook = state->hook,
139 .indev = indev, 136 .indev = state->in,
140 .outdev = outdev, 137 .outdev = state->out,
141 .okfn = okfn, 138 .okfn = state->okfn,
142 .size = sizeof(*entry) + afinfo->route_key_size, 139 .size = sizeof(*entry) + afinfo->route_key_size,
143 }; 140 };
144 141
@@ -171,6 +168,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
171 struct sk_buff *skb = entry->skb; 168 struct sk_buff *skb = entry->skb;
172 struct nf_hook_ops *elem = entry->elem; 169 struct nf_hook_ops *elem = entry->elem;
173 const struct nf_afinfo *afinfo; 170 const struct nf_afinfo *afinfo;
171 struct nf_hook_state state;
174 int err; 172 int err;
175 173
176 rcu_read_lock(); 174 rcu_read_lock();
@@ -189,12 +187,17 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
189 verdict = NF_DROP; 187 verdict = NF_DROP;
190 } 188 }
191 189
190 state.hook = entry->hook;
191 state.thresh = INT_MIN;
192 state.pf = entry->pf;
193 state.in = entry->indev;
194 state.out = entry->outdev;
195 state.okfn = entry->okfn;
196
192 if (verdict == NF_ACCEPT) { 197 if (verdict == NF_ACCEPT) {
193 next_hook: 198 next_hook:
194 verdict = nf_iterate(&nf_hooks[entry->pf][entry->hook], 199 verdict = nf_iterate(&nf_hooks[entry->pf][entry->hook],
195 skb, entry->hook, 200 skb, &state, &elem);
196 entry->indev, entry->outdev, &elem,
197 entry->okfn, INT_MIN);
198 } 201 }
199 202
200 switch (verdict & NF_VERDICT_MASK) { 203 switch (verdict & NF_VERDICT_MASK) {
@@ -205,9 +208,8 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
205 local_bh_enable(); 208 local_bh_enable();
206 break; 209 break;
207 case NF_QUEUE: 210 case NF_QUEUE:
208 err = nf_queue(skb, elem, entry->pf, entry->hook, 211 err = nf_queue(skb, elem, &state,
209 entry->indev, entry->outdev, entry->okfn, 212 verdict >> NF_VERDICT_QBITS);
210 verdict >> NF_VERDICT_QBITS);
211 if (err < 0) { 213 if (err < 0) {
212 if (err == -ECANCELED) 214 if (err == -ECANCELED)
213 goto next_hook; 215 goto next_hook;