aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/netfilter/core.c')
-rw-r--r--net/netfilter/core.c86
1 files changed, 28 insertions, 58 deletions
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 004af030ef1a..de30e08d58f2 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -302,70 +302,40 @@ void _nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n)
}
EXPORT_SYMBOL(_nf_unregister_hooks);
-unsigned int nf_iterate(struct sk_buff *skb,
- struct nf_hook_state *state,
- struct nf_hook_entry **entryp)
+/* Returns 1 if okfn() needs to be executed by the caller,
+ * -EPERM for NF_DROP, 0 otherwise. Caller must hold rcu_read_lock. */
+int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
+ struct nf_hook_entry *entry)
{
unsigned int verdict;
+ int ret;
- /*
- * The caller must not block between calls to this
- * function because of risk of continuing from deleted element.
- */
- while (*entryp) {
- if (state->thresh > (*entryp)->ops.priority) {
- *entryp = rcu_dereference((*entryp)->next);
- continue;
- }
-
- /* Optimization: we don't need to hold module
- reference here, since function can't sleep. --RR */
-repeat:
- verdict = (*entryp)->ops.hook((*entryp)->ops.priv, skb, state);
- if (verdict != NF_ACCEPT) {
-#ifdef CONFIG_NETFILTER_DEBUG
- if (unlikely((verdict & NF_VERDICT_MASK)
- > NF_MAX_VERDICT)) {
- NFDEBUG("Evil return from %p(%u).\n",
- (*entryp)->ops.hook, state->hook);
- *entryp = rcu_dereference((*entryp)->next);
+ do {
+ verdict = entry->ops.hook(entry->ops.priv, skb, state);
+ switch (verdict & NF_VERDICT_MASK) {
+ case NF_ACCEPT:
+ entry = rcu_dereference(entry->next);
+ break;
+ case NF_DROP:
+ kfree_skb(skb);
+ ret = NF_DROP_GETERR(verdict);
+ if (ret == 0)
+ ret = -EPERM;
+ return ret;
+ case NF_QUEUE:
+ ret = nf_queue(skb, state, &entry, verdict);
+ if (ret == 1 && entry)
continue;
- }
-#endif
- if (verdict != NF_REPEAT)
- return verdict;
- goto repeat;
+ return ret;
+ default:
+ /* Implicit handling for NF_STOLEN, as well as any other
+ * non conventional verdicts.
+ */
+ return 0;
}
- *entryp = rcu_dereference((*entryp)->next);
- }
- return NF_ACCEPT;
-}
-
+ } while (entry);
-/* Returns 1 if okfn() needs to be executed by the caller,
- * -EPERM for NF_DROP, 0 otherwise. Caller must hold rcu_read_lock. */
-int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state)
-{
- struct nf_hook_entry *entry;
- unsigned int verdict;
- int ret = 0;
-
- entry = rcu_dereference(state->hook_entries);
-next_hook:
- verdict = nf_iterate(skb, state, &entry);
- if (verdict == NF_ACCEPT || verdict == NF_STOP) {
- ret = 1;
- } else if ((verdict & NF_VERDICT_MASK) == NF_DROP) {
- kfree_skb(skb);
- ret = NF_DROP_GETERR(verdict);
- if (ret == 0)
- ret = -EPERM;
- } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
- ret = nf_queue(skb, state, &entry, verdict);
- if (ret == 1 && entry)
- goto next_hook;
- }
- return ret;
+ return 1;
}
EXPORT_SYMBOL(nf_hook_slow);