aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2011-01-18 09:27:28 -0500
committerPatrick McHardy <kaber@trash.net>2011-01-18 09:27:28 -0500
commitf15850861860636c905b33a9a5be3dcbc2b0d56a (patch)
tree463d73647de2a43138bdd8259c259137a3bb3e3b /net
parent5f2cafe73671d865af88494159f3e8c1b322e1c5 (diff)
netfilter: nfnetlink_queue: return error number to caller
instead of returning -1 on error, return an error number to allow the caller to handle some errors differently. ECANCELED is used to indicate that the hook is going away and should be ignored. A followup patch will introduce more 'ignore this hook' conditions, (depending on queue settings) and will move kfree_skb responsibility to the caller. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/core.c6
-rw-r--r--net/netfilter/nf_queue.c44
-rw-r--r--net/netfilter/nfnetlink_queue.c22
3 files changed, 49 insertions, 23 deletions
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index e69d537362c7..91d66d2f8cd9 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -179,9 +179,11 @@ next_hook:
179 if (ret == 0) 179 if (ret == 0)
180 ret = -EPERM; 180 ret = -EPERM;
181 } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { 181 } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
182 if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn, 182 ret = nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
183 verdict >> NF_VERDICT_BITS)) 183 verdict >> NF_VERDICT_BITS);
184 if (ret == -ECANCELED)
184 goto next_hook; 185 goto next_hook;
186 ret = 0;
185 } 187 }
186 rcu_read_unlock(); 188 rcu_read_unlock();
187 return ret; 189 return ret;
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index 1876f7411561..ad25c7e726bc 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -125,7 +125,7 @@ static int __nf_queue(struct sk_buff *skb,
125 int (*okfn)(struct sk_buff *), 125 int (*okfn)(struct sk_buff *),
126 unsigned int queuenum) 126 unsigned int queuenum)
127{ 127{
128 int status; 128 int status = -ENOENT;
129 struct nf_queue_entry *entry = NULL; 129 struct nf_queue_entry *entry = NULL;
130#ifdef CONFIG_BRIDGE_NETFILTER 130#ifdef CONFIG_BRIDGE_NETFILTER
131 struct net_device *physindev; 131 struct net_device *physindev;
@@ -146,8 +146,10 @@ static int __nf_queue(struct sk_buff *skb,
146 goto err_unlock; 146 goto err_unlock;
147 147
148 entry = kmalloc(sizeof(*entry) + afinfo->route_key_size, GFP_ATOMIC); 148 entry = kmalloc(sizeof(*entry) + afinfo->route_key_size, GFP_ATOMIC);
149 if (!entry) 149 if (!entry) {
150 status = -ENOMEM;
150 goto err_unlock; 151 goto err_unlock;
152 }
151 153
152 *entry = (struct nf_queue_entry) { 154 *entry = (struct nf_queue_entry) {
153 .skb = skb, 155 .skb = skb,
@@ -163,9 +165,8 @@ static int __nf_queue(struct sk_buff *skb,
163 if (!try_module_get(entry->elem->owner)) { 165 if (!try_module_get(entry->elem->owner)) {
164 rcu_read_unlock(); 166 rcu_read_unlock();
165 kfree(entry); 167 kfree(entry);
166 return 0; 168 return -ECANCELED;
167 } 169 }
168
169 /* Bump dev refs so they don't vanish while packet is out */ 170 /* Bump dev refs so they don't vanish while packet is out */
170 if (indev) 171 if (indev)
171 dev_hold(indev); 172 dev_hold(indev);
@@ -192,14 +193,14 @@ static int __nf_queue(struct sk_buff *skb,
192 goto err; 193 goto err;
193 } 194 }
194 195
195 return 1; 196 return 0;
196 197
197err_unlock: 198err_unlock:
198 rcu_read_unlock(); 199 rcu_read_unlock();
199err: 200err:
200 kfree_skb(skb); 201 kfree_skb(skb);
201 kfree(entry); 202 kfree(entry);
202 return 1; 203 return status;
203} 204}
204 205
205int nf_queue(struct sk_buff *skb, 206int nf_queue(struct sk_buff *skb,
@@ -211,6 +212,8 @@ int nf_queue(struct sk_buff *skb,
211 unsigned int queuenum) 212 unsigned int queuenum)
212{ 213{
213 struct sk_buff *segs; 214 struct sk_buff *segs;
215 int err;
216 unsigned int queued;
214 217
215 if (!skb_is_gso(skb)) 218 if (!skb_is_gso(skb))
216 return __nf_queue(skb, elem, pf, hook, indev, outdev, okfn, 219 return __nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
@@ -227,19 +230,32 @@ int nf_queue(struct sk_buff *skb,
227 230
228 segs = skb_gso_segment(skb, 0); 231 segs = skb_gso_segment(skb, 0);
229 kfree_skb(skb); 232 kfree_skb(skb);
233 /* Does not use PTR_ERR to limit the number of error codes that can be
234 * returned by nf_queue. For instance, callers rely on -ECANCELED to mean
235 * 'ignore this hook'.
236 */
230 if (IS_ERR(segs)) 237 if (IS_ERR(segs))
231 return 1; 238 return -EINVAL;
232 239
240 queued = 0;
241 err = 0;
233 do { 242 do {
234 struct sk_buff *nskb = segs->next; 243 struct sk_buff *nskb = segs->next;
235 244
236 segs->next = NULL; 245 segs->next = NULL;
237 if (!__nf_queue(segs, elem, pf, hook, indev, outdev, okfn, 246 if (err == 0)
238 queuenum)) 247 err = __nf_queue(segs, elem, pf, hook, indev,
248 outdev, okfn, queuenum);
249 if (err == 0)
250 queued++;
251 else
239 kfree_skb(segs); 252 kfree_skb(segs);
240 segs = nskb; 253 segs = nskb;
241 } while (segs); 254 } while (segs);
242 return 1; 255
256 if (unlikely(err && queued))
257 err = 0;
258 return err;
243} 259}
244 260
245void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) 261void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
@@ -247,6 +263,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
247 struct sk_buff *skb = entry->skb; 263 struct sk_buff *skb = entry->skb;
248 struct list_head *elem = &entry->elem->list; 264 struct list_head *elem = &entry->elem->list;
249 const struct nf_afinfo *afinfo; 265 const struct nf_afinfo *afinfo;
266 int err;
250 267
251 rcu_read_lock(); 268 rcu_read_lock();
252 269
@@ -280,9 +297,10 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
280 local_bh_enable(); 297 local_bh_enable();
281 break; 298 break;
282 case NF_QUEUE: 299 case NF_QUEUE:
283 if (!__nf_queue(skb, elem, entry->pf, entry->hook, 300 err = __nf_queue(skb, elem, entry->pf, entry->hook,
284 entry->indev, entry->outdev, entry->okfn, 301 entry->indev, entry->outdev, entry->okfn,
285 verdict >> NF_VERDICT_BITS)) 302 verdict >> NF_VERDICT_BITS);
303 if (err == -ECANCELED)
286 goto next_hook; 304 goto next_hook;
287 break; 305 break;
288 case NF_STOLEN: 306 case NF_STOLEN:
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 68e67d19724d..b83123f12b42 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -387,25 +387,31 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
387{ 387{
388 struct sk_buff *nskb; 388 struct sk_buff *nskb;
389 struct nfqnl_instance *queue; 389 struct nfqnl_instance *queue;
390 int err; 390 int err = -ENOBUFS;
391 391
392 /* rcu_read_lock()ed by nf_hook_slow() */ 392 /* rcu_read_lock()ed by nf_hook_slow() */
393 queue = instance_lookup(queuenum); 393 queue = instance_lookup(queuenum);
394 if (!queue) 394 if (!queue) {
395 err = -ESRCH;
395 goto err_out; 396 goto err_out;
397 }
396 398
397 if (queue->copy_mode == NFQNL_COPY_NONE) 399 if (queue->copy_mode == NFQNL_COPY_NONE) {
400 err = -EINVAL;
398 goto err_out; 401 goto err_out;
402 }
399 403
400 nskb = nfqnl_build_packet_message(queue, entry); 404 nskb = nfqnl_build_packet_message(queue, entry);
401 if (nskb == NULL) 405 if (nskb == NULL) {
406 err = -ENOMEM;
402 goto err_out; 407 goto err_out;
403 408 }
404 spin_lock_bh(&queue->lock); 409 spin_lock_bh(&queue->lock);
405 410
406 if (!queue->peer_pid) 411 if (!queue->peer_pid) {
412 err = -EINVAL;
407 goto err_out_free_nskb; 413 goto err_out_free_nskb;
408 414 }
409 if (queue->queue_total >= queue->queue_maxlen) { 415 if (queue->queue_total >= queue->queue_maxlen) {
410 queue->queue_dropped++; 416 queue->queue_dropped++;
411 if (net_ratelimit()) 417 if (net_ratelimit())
@@ -432,7 +438,7 @@ err_out_free_nskb:
432err_out_unlock: 438err_out_unlock:
433 spin_unlock_bh(&queue->lock); 439 spin_unlock_bh(&queue->lock);
434err_out: 440err_out:
435 return -1; 441 return err;
436} 442}
437 443
438static int 444static int