aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/netfilter/nf_queue.c49
1 files changed, 28 insertions, 21 deletions
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index 5ccf01e35390..1d91e77ba4c2 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -66,6 +66,33 @@ static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
66 module_put(entry->elem->owner); 66 module_put(entry->elem->owner);
67} 67}
68 68
69/* Bump dev refs so they don't vanish while packet is out */
70static bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)
71{
72 if (!try_module_get(entry->elem->owner))
73 return false;
74
75 if (entry->indev)
76 dev_hold(entry->indev);
77 if (entry->outdev)
78 dev_hold(entry->outdev);
79#ifdef CONFIG_BRIDGE_NETFILTER
80 if (entry->skb->nf_bridge) {
81 struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge;
82 struct net_device *physdev;
83
84 physdev = nf_bridge->physindev;
85 if (physdev)
86 dev_hold(physdev);
87 physdev = nf_bridge->physoutdev;
88 if (physdev)
89 dev_hold(physdev);
90 }
91#endif
92
93 return true;
94}
95
69/* 96/*
70 * Any packet that leaves via this function must come back 97 * Any packet that leaves via this function must come back
71 * through nf_reinject(). 98 * through nf_reinject().
@@ -80,10 +107,6 @@ static int __nf_queue(struct sk_buff *skb,
80{ 107{
81 int status = -ENOENT; 108 int status = -ENOENT;
82 struct nf_queue_entry *entry = NULL; 109 struct nf_queue_entry *entry = NULL;
83#ifdef CONFIG_BRIDGE_NETFILTER
84 struct net_device *physindev;
85 struct net_device *physoutdev;
86#endif
87 const struct nf_afinfo *afinfo; 110 const struct nf_afinfo *afinfo;
88 const struct nf_queue_handler *qh; 111 const struct nf_queue_handler *qh;
89 112
@@ -116,26 +139,10 @@ static int __nf_queue(struct sk_buff *skb,
116 .okfn = okfn, 139 .okfn = okfn,
117 }; 140 };
118 141
119 /* If it's going away, ignore hook. */ 142 if (!nf_queue_entry_get_refs(entry)) {
120 if (!try_module_get(entry->elem->owner)) {
121 status = -ECANCELED; 143 status = -ECANCELED;
122 goto err_unlock; 144 goto err_unlock;
123 } 145 }
124 /* Bump dev refs so they don't vanish while packet is out */
125 if (indev)
126 dev_hold(indev);
127 if (outdev)
128 dev_hold(outdev);
129#ifdef CONFIG_BRIDGE_NETFILTER
130 if (skb->nf_bridge) {
131 physindev = skb->nf_bridge->physindev;
132 if (physindev)
133 dev_hold(physindev);
134 physoutdev = skb->nf_bridge->physoutdev;
135 if (physoutdev)
136 dev_hold(physoutdev);
137 }
138#endif
139 skb_dst_force(skb); 146 skb_dst_force(skb);
140 afinfo->saveroute(skb, entry); 147 afinfo->saveroute(skb, entry);
141 status = qh->outfn(entry, queuenum); 148 status = qh->outfn(entry, queuenum);