aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/netfilter/br_netfilter.h6
-rw-r--r--net/bridge/br_netfilter_hooks.c60
-rw-r--r--net/bridge/br_netfilter_ipv6.c12
3 files changed, 62 insertions, 16 deletions
diff --git a/include/net/netfilter/br_netfilter.h b/include/net/netfilter/br_netfilter.h
index e8d1448425a7..0b0c35c37125 100644
--- a/include/net/netfilter/br_netfilter.h
+++ b/include/net/netfilter/br_netfilter.h
@@ -15,6 +15,12 @@ static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
15 15
16void nf_bridge_update_protocol(struct sk_buff *skb); 16void nf_bridge_update_protocol(struct sk_buff *skb);
17 17
18int br_nf_hook_thresh(unsigned int hook, struct net *net, struct sock *sk,
19 struct sk_buff *skb, struct net_device *indev,
20 struct net_device *outdev,
21 int (*okfn)(struct net *, struct sock *,
22 struct sk_buff *));
23
18static inline struct nf_bridge_info * 24static inline struct nf_bridge_info *
19nf_bridge_info_get(const struct sk_buff *skb) 25nf_bridge_info_get(const struct sk_buff *skb)
20{ 26{
diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c
index 77e7f69bf80d..6029af47377d 100644
--- a/net/bridge/br_netfilter_hooks.c
+++ b/net/bridge/br_netfilter_hooks.c
@@ -30,6 +30,7 @@
30#include <linux/netfilter_ipv6.h> 30#include <linux/netfilter_ipv6.h>
31#include <linux/netfilter_arp.h> 31#include <linux/netfilter_arp.h>
32#include <linux/in_route.h> 32#include <linux/in_route.h>
33#include <linux/rculist.h>
33#include <linux/inetdevice.h> 34#include <linux/inetdevice.h>
34 35
35#include <net/ip.h> 36#include <net/ip.h>
@@ -395,11 +396,10 @@ bridged_dnat:
395 skb->dev = nf_bridge->physindev; 396 skb->dev = nf_bridge->physindev;
396 nf_bridge_update_protocol(skb); 397 nf_bridge_update_protocol(skb);
397 nf_bridge_push_encap_header(skb); 398 nf_bridge_push_encap_header(skb);
398 NF_HOOK_THRESH(NFPROTO_BRIDGE, 399 br_nf_hook_thresh(NF_BR_PRE_ROUTING,
399 NF_BR_PRE_ROUTING, 400 net, sk, skb, skb->dev,
400 net, sk, skb, skb->dev, NULL, 401 NULL,
401 br_nf_pre_routing_finish_bridge, 402 br_nf_pre_routing_finish);
402 1);
403 return 0; 403 return 0;
404 } 404 }
405 ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr); 405 ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr);
@@ -417,10 +417,8 @@ bridged_dnat:
417 skb->dev = nf_bridge->physindev; 417 skb->dev = nf_bridge->physindev;
418 nf_bridge_update_protocol(skb); 418 nf_bridge_update_protocol(skb);
419 nf_bridge_push_encap_header(skb); 419 nf_bridge_push_encap_header(skb);
420 NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, net, sk, skb, 420 br_nf_hook_thresh(NF_BR_PRE_ROUTING, net, sk, skb, skb->dev, NULL,
421 skb->dev, NULL, 421 br_handle_frame_finish);
422 br_handle_frame_finish, 1);
423
424 return 0; 422 return 0;
425} 423}
426 424
@@ -992,6 +990,50 @@ static struct notifier_block brnf_notifier __read_mostly = {
992 .notifier_call = brnf_device_event, 990 .notifier_call = brnf_device_event,
993}; 991};
994 992
993/* recursively invokes nf_hook_slow (again), skipping already-called
994 * hooks (< NF_BR_PRI_BRNF).
995 *
996 * Called with rcu read lock held.
997 */
998int br_nf_hook_thresh(unsigned int hook, struct net *net,
999 struct sock *sk, struct sk_buff *skb,
1000 struct net_device *indev,
1001 struct net_device *outdev,
1002 int (*okfn)(struct net *, struct sock *,
1003 struct sk_buff *))
1004{
1005 struct nf_hook_ops *elem;
1006 struct nf_hook_state state;
1007 struct list_head *head;
1008 int ret;
1009
1010 head = &net->nf.hooks[NFPROTO_BRIDGE][hook];
1011
1012 list_for_each_entry_rcu(elem, head, list) {
1013 struct nf_hook_ops *next;
1014
1015 next = list_entry_rcu(list_next_rcu(&elem->list),
1016 struct nf_hook_ops, list);
1017 if (next->priority <= NF_BR_PRI_BRNF)
1018 continue;
1019 }
1020
1021 if (&elem->list == head)
1022 return okfn(net, sk, skb);
1023
1024 /* We may already have this, but read-locks nest anyway */
1025 rcu_read_lock();
1026 nf_hook_state_init(&state, head, hook, NF_BR_PRI_BRNF + 1,
1027 NFPROTO_BRIDGE, indev, outdev, sk, net, okfn);
1028
1029 ret = nf_hook_slow(skb, &state);
1030 rcu_read_unlock();
1031 if (ret == 1)
1032 ret = okfn(net, sk, skb);
1033
1034 return ret;
1035}
1036
995#ifdef CONFIG_SYSCTL 1037#ifdef CONFIG_SYSCTL
996static 1038static
997int brnf_sysctl_call_tables(struct ctl_table *ctl, int write, 1039int brnf_sysctl_call_tables(struct ctl_table *ctl, int write,
diff --git a/net/bridge/br_netfilter_ipv6.c b/net/bridge/br_netfilter_ipv6.c
index 5e59a8457e7b..5989661c659f 100644
--- a/net/bridge/br_netfilter_ipv6.c
+++ b/net/bridge/br_netfilter_ipv6.c
@@ -187,10 +187,9 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
187 skb->dev = nf_bridge->physindev; 187 skb->dev = nf_bridge->physindev;
188 nf_bridge_update_protocol(skb); 188 nf_bridge_update_protocol(skb);
189 nf_bridge_push_encap_header(skb); 189 nf_bridge_push_encap_header(skb);
190 NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, 190 br_nf_hook_thresh(NF_BR_PRE_ROUTING,
191 net, sk, skb, skb->dev, NULL, 191 net, sk, skb, skb->dev, NULL,
192 br_nf_pre_routing_finish_bridge, 192 br_nf_pre_routing_finish_bridge);
193 1);
194 return 0; 193 return 0;
195 } 194 }
196 ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr); 195 ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr);
@@ -207,9 +206,8 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
207 skb->dev = nf_bridge->physindev; 206 skb->dev = nf_bridge->physindev;
208 nf_bridge_update_protocol(skb); 207 nf_bridge_update_protocol(skb);
209 nf_bridge_push_encap_header(skb); 208 nf_bridge_push_encap_header(skb);
210 NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, net, sk, skb, 209 br_nf_hook_thresh(NF_BR_PRE_ROUTING, net, sk, skb,
211 skb->dev, NULL, 210 skb->dev, NULL, br_handle_frame_finish);
212 br_handle_frame_finish, 1);
213 211
214 return 0; 212 return 0;
215} 213}