These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / netfilter / nf_queue.c
index 2e88032..5baa8e2 100644 (file)
@@ -69,19 +69,14 @@ void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
                        dev_put(physdev);
        }
 #endif
-       /* Drop reference to owner of hook which queued us. */
-       module_put(entry->elem->owner);
 }
 EXPORT_SYMBOL_GPL(nf_queue_entry_release_refs);
 
 /* Bump dev refs so they don't vanish while packet is out */
-bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)
+void nf_queue_entry_get_refs(struct nf_queue_entry *entry)
 {
        struct nf_hook_state *state = &entry->state;
 
-       if (!try_module_get(entry->elem->owner))
-               return false;
-
        if (state->in)
                dev_hold(state->in);
        if (state->out)
@@ -100,11 +95,20 @@ bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)
                        dev_hold(physdev);
        }
 #endif
-
-       return true;
 }
 EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs);
 
+void nf_queue_nf_hook_drop(struct net *net, struct nf_hook_ops *ops)
+{
+       const struct nf_queue_handler *qh;
+
+       rcu_read_lock();
+       qh = rcu_dereference(queue_handler);
+       if (qh)
+               qh->nf_hook_drop(net, ops);
+       rcu_read_unlock();
+}
+
 /*
  * Any packet that leaves via this function must come back
  * through nf_reinject().
@@ -120,22 +124,20 @@ int nf_queue(struct sk_buff *skb,
        const struct nf_queue_handler *qh;
 
        /* QUEUE == DROP if no one is waiting, to be safe. */
-       rcu_read_lock();
-
        qh = rcu_dereference(queue_handler);
        if (!qh) {
                status = -ESRCH;
-               goto err_unlock;
+               goto err;
        }
 
        afinfo = nf_get_afinfo(state->pf);
        if (!afinfo)
-               goto err_unlock;
+               goto err;
 
        entry = kmalloc(sizeof(*entry) + afinfo->route_key_size, GFP_ATOMIC);
        if (!entry) {
                status = -ENOMEM;
-               goto err_unlock;
+               goto err;
        }
 
        *entry = (struct nf_queue_entry) {
@@ -145,16 +147,11 @@ int nf_queue(struct sk_buff *skb,
                .size   = sizeof(*entry) + afinfo->route_key_size,
        };
 
-       if (!nf_queue_entry_get_refs(entry)) {
-               status = -ECANCELED;
-               goto err_unlock;
-       }
+       nf_queue_entry_get_refs(entry);
        skb_dst_force(skb);
        afinfo->saveroute(skb, entry);
        status = qh->outfn(entry, queuenum);
 
-       rcu_read_unlock();
-
        if (status < 0) {
                nf_queue_entry_release_refs(entry);
                goto err;
@@ -162,8 +159,6 @@ int nf_queue(struct sk_buff *skb,
 
        return 0;
 
-err_unlock:
-       rcu_read_unlock();
 err:
        kfree(entry);
        return status;
@@ -176,19 +171,15 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
        const struct nf_afinfo *afinfo;
        int err;
 
-       rcu_read_lock();
-
        nf_queue_entry_release_refs(entry);
 
        /* Continue traversal iff userspace said ok... */
-       if (verdict == NF_REPEAT) {
-               elem = list_entry(elem->list.prev, struct nf_hook_ops, list);
-               verdict = NF_ACCEPT;
-       }
+       if (verdict == NF_REPEAT)
+               verdict = elem->hook(elem->priv, skb, &entry->state);
 
        if (verdict == NF_ACCEPT) {
                afinfo = nf_get_afinfo(entry->state.pf);
-               if (!afinfo || afinfo->reroute(skb, entry) < 0)
+               if (!afinfo || afinfo->reroute(entry->state.net, skb, entry) < 0)
                        verdict = NF_DROP;
        }
 
@@ -196,7 +187,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
 
        if (verdict == NF_ACCEPT) {
        next_hook:
-               verdict = nf_iterate(&nf_hooks[entry->state.pf][entry->state.hook],
+               verdict = nf_iterate(entry->state.hook_list,
                                     skb, &entry->state, &elem);
        }
 
@@ -204,15 +195,13 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
        case NF_ACCEPT:
        case NF_STOP:
                local_bh_disable();
-               entry->state.okfn(entry->state.sk, skb);
+               entry->state.okfn(entry->state.net, entry->state.sk, skb);
                local_bh_enable();
                break;
        case NF_QUEUE:
                err = nf_queue(skb, elem, &entry->state,
                               verdict >> NF_VERDICT_QBITS);
                if (err < 0) {
-                       if (err == -ECANCELED)
-                               goto next_hook;
                        if (err == -ESRCH &&
                           (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS))
                                goto next_hook;
@@ -224,7 +213,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
        default:
                kfree_skb(skb);
        }
-       rcu_read_unlock();
+
        kfree(entry);
 }
 EXPORT_SYMBOL(nf_reinject);