Commit 119e52e6 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso

netfilter: nf_queue: place bridge physports into queue_entry struct

The refcount is done via entry->skb, which does work fine.
Major problem: When putting the refcount of the bridge ports, we
must always put the references while the skb is still around.

However, we will need to put the references after okfn() to avoid
a possible 1 -> 0 -> 1 refcount transition, so we cannot use the
skb pointer anymore.

Place the physports in the queue entry structure instead to allow
for refcounting changes in the next patch.
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent dd3cc111
...@@ -14,7 +14,10 @@ struct nf_queue_entry { ...@@ -14,7 +14,10 @@ struct nf_queue_entry {
struct sk_buff *skb; struct sk_buff *skb;
unsigned int id; unsigned int id;
unsigned int hook_index; /* index in hook_entries->hook[] */ unsigned int hook_index; /* index in hook_entries->hook[] */
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
struct net_device *physin;
struct net_device *physout;
#endif
struct nf_hook_state state; struct nf_hook_state state;
u16 size; /* sizeof(entry) + saved route keys */ u16 size; /* sizeof(entry) + saved route keys */
......
...@@ -46,24 +46,6 @@ void nf_unregister_queue_handler(struct net *net) ...@@ -46,24 +46,6 @@ void nf_unregister_queue_handler(struct net *net)
} }
EXPORT_SYMBOL(nf_unregister_queue_handler); EXPORT_SYMBOL(nf_unregister_queue_handler);
static void nf_queue_entry_release_br_nf_refs(struct sk_buff *skb)
{
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
if (nf_bridge) {
struct net_device *physdev;
physdev = nf_bridge_get_physindev(skb);
if (physdev)
dev_put(physdev);
physdev = nf_bridge_get_physoutdev(skb);
if (physdev)
dev_put(physdev);
}
#endif
}
static void nf_queue_entry_release_refs(struct nf_queue_entry *entry) static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
{ {
struct nf_hook_state *state = &entry->state; struct nf_hook_state *state = &entry->state;
...@@ -76,7 +58,12 @@ static void nf_queue_entry_release_refs(struct nf_queue_entry *entry) ...@@ -76,7 +58,12 @@ static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
if (state->sk) if (state->sk)
sock_put(state->sk); sock_put(state->sk);
nf_queue_entry_release_br_nf_refs(entry->skb); #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
if (entry->physin)
dev_put(entry->physin);
if (entry->physout)
dev_put(entry->physout);
#endif
} }
void nf_queue_entry_free(struct nf_queue_entry *entry) void nf_queue_entry_free(struct nf_queue_entry *entry)
...@@ -86,20 +73,19 @@ void nf_queue_entry_free(struct nf_queue_entry *entry) ...@@ -86,20 +73,19 @@ void nf_queue_entry_free(struct nf_queue_entry *entry)
} }
EXPORT_SYMBOL_GPL(nf_queue_entry_free); EXPORT_SYMBOL_GPL(nf_queue_entry_free);
static void nf_queue_entry_get_br_nf_refs(struct sk_buff *skb) static void __nf_queue_entry_init_physdevs(struct nf_queue_entry *entry)
{ {
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb); const struct sk_buff *skb = entry->skb;
struct nf_bridge_info *nf_bridge;
nf_bridge = nf_bridge_info_get(skb);
if (nf_bridge) { if (nf_bridge) {
struct net_device *physdev; entry->physin = nf_bridge_get_physindev(skb);
entry->physout = nf_bridge_get_physoutdev(skb);
physdev = nf_bridge_get_physindev(skb); } else {
if (physdev) entry->physin = NULL;
dev_hold(physdev); entry->physout = NULL;
physdev = nf_bridge_get_physoutdev(skb);
if (physdev)
dev_hold(physdev);
} }
#endif #endif
} }
...@@ -116,7 +102,12 @@ void nf_queue_entry_get_refs(struct nf_queue_entry *entry) ...@@ -116,7 +102,12 @@ void nf_queue_entry_get_refs(struct nf_queue_entry *entry)
if (state->sk) if (state->sk)
sock_hold(state->sk); sock_hold(state->sk);
nf_queue_entry_get_br_nf_refs(entry->skb); #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
if (entry->physin)
dev_hold(entry->physin);
if (entry->physout)
dev_hold(entry->physout);
#endif
} }
EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs); EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs);
...@@ -207,6 +198,8 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state, ...@@ -207,6 +198,8 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
.size = sizeof(*entry) + route_key_size, .size = sizeof(*entry) + route_key_size,
}; };
__nf_queue_entry_init_physdevs(entry);
nf_queue_entry_get_refs(entry); nf_queue_entry_get_refs(entry);
switch (entry->state.pf) { switch (entry->state.pf) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment