NF_BR_PRI_LAST = INT_MAX,
 };
 
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
 
 #define BRNF_PKT_TYPE                  0x01
 #define BRNF_BRIDGED_DNAT              0x02
 
 };
 #endif
 
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
 struct nf_bridge_info {
        atomic_t                use;
        unsigned int            mask;
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        struct nf_conntrack     *nfct;
 #endif
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        struct nf_bridge_info   *nf_bridge;
 #endif
 
                atomic_inc(&nfct->use);
 }
 #endif
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
 static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge)
 {
        if (nf_bridge && atomic_dec_and_test(&nf_bridge->use))
        nf_conntrack_put(skb->nfct);
        skb->nfct = NULL;
 #endif
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        nf_bridge_put(skb->nf_bridge);
        skb->nf_bridge = NULL;
 #endif
        nf_conntrack_get(src->nfct);
        dst->nfctinfo = src->nfctinfo;
 #endif
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        dst->nf_bridge  = src->nf_bridge;
        nf_bridge_get(src->nf_bridge);
 #endif
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        nf_conntrack_put(dst->nfct);
 #endif
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        nf_bridge_put(dst->nf_bridge);
 #endif
        __nf_copy(dst, src);
 
        return 0;
 }
 
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
 static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb)
 {
        unsigned int seq, hh_alen;
 
 
        nf_ct_attach(nskb, oldskb);
 
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        /* If we use ip_local_out for bridged traffic, the MAC source on
         * the RST will be ours, instead of the destination's.  This confuses
         * some routers/firewalls, and they drop the packet.  So we need to
 
 
        nf_ct_attach(nskb, oldskb);
 
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        /* If we use ip6_local_out for bridged traffic, the MAC source on
         * the RST will be ours, instead of the destination's.  This confuses
         * some routers/firewalls, and they drop the packet.  So we need to
 
          If unsure, say Y.
 
 config BRIDGE_NETFILTER
-       bool "Bridged IP/ARP packets filtering"
-       depends on BRIDGE && NETFILTER && INET
+       tristate "Bridged IP/ARP packets filtering"
+       depends on (BRIDGE || BRIDGE=n)
+       depends on NETFILTER && INET
        depends on NETFILTER_ADVANCED
-       default y
+       default m
        ---help---
          Enabling this option will let arptables resp. iptables see bridged
          ARP resp. IP traffic. If you want a bridging firewall, you probably
 
 
 bridge-y       := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
                        br_ioctl.o br_stp.o br_stp_bpdu.o \
-                       br_stp_if.o br_stp_timer.o br_netlink.o
+                       br_stp_if.o br_stp_timer.o br_netlink.o \
+                       br_nf_core.o
 
 bridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.o
 
-bridge-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o
+obj-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o
 
 bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o br_mdb.o
 
 
        if (err)
                goto err_out1;
 
-       err = br_netfilter_init();
+       err = br_nf_core_init();
        if (err)
                goto err_out2;
 
        br_fdb_test_addr_hook = br_fdb_test_addr;
 #endif
 
+       pr_info("bridge: automatic filtering via arp/ip/ip6tables has been "
+               "deprecated. Update your scripts to load br_netfilter if you "
+               "need this.\n");
+
        return 0;
+
 err_out4:
        unregister_netdevice_notifier(&br_device_notifier);
 err_out3:
-       br_netfilter_fini();
+       br_nf_core_fini();
 err_out2:
        unregister_pernet_subsys(&br_net_ops);
 err_out1:
 static void __exit br_deinit(void)
 {
        stp_proto_unregister(&br_stp_proto);
-
        br_netlink_fini();
        unregister_netdevice_notifier(&br_device_notifier);
        brioctl_set(NULL);
-
        unregister_pernet_subsys(&br_net_ops);
 
        rcu_barrier(); /* Wait for completion of call_rcu()'s */
 
-       br_netfilter_fini();
+       br_nf_core_fini();
 #if IS_ENABLED(CONFIG_ATM_LANE)
        br_fdb_test_addr_hook = NULL;
 #endif
-
        br_fdb_fini();
 }
 
 
        u16 vid = 0;
 
        rcu_read_lock();
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) {
                br_nf_pre_routing_finish_bridge_slow(skb);
                rcu_read_unlock();
 
        dev->mtu = new_mtu;
 
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        /* remember the MTU in the rtable for PMTU */
        dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu);
 #endif
 
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit);
 
 int br_forward_finish(struct sk_buff *skb)
 {
                       br_dev_queue_push_xmit);
 
 }
+EXPORT_SYMBOL_GPL(br_forward_finish);
 
 static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
 {
 
        kfree_skb(skb);
        goto out;
 }
+EXPORT_SYMBOL_GPL(br_handle_frame_finish);
 
 /* note: already called with rcu_read_lock */
 static int br_handle_local_finish(struct sk_buff *skb)
 
         pppoe_proto(skb) == htons(PPP_IPV6) && \
         brnf_filter_pppoe_tagged)
 
-static void fake_update_pmtu(struct dst_entry *dst, struct sock *sk,
-                            struct sk_buff *skb, u32 mtu)
-{
-}
-
-static void fake_redirect(struct dst_entry *dst, struct sock *sk,
-                         struct sk_buff *skb)
-{
-}
-
-static u32 *fake_cow_metrics(struct dst_entry *dst, unsigned long old)
-{
-       return NULL;
-}
-
-static struct neighbour *fake_neigh_lookup(const struct dst_entry *dst,
-                                          struct sk_buff *skb,
-                                          const void *daddr)
-{
-       return NULL;
-}
-
-static unsigned int fake_mtu(const struct dst_entry *dst)
-{
-       return dst->dev->mtu;
-}
-
-static struct dst_ops fake_dst_ops = {
-       .family =               AF_INET,
-       .protocol =             cpu_to_be16(ETH_P_IP),
-       .update_pmtu =          fake_update_pmtu,
-       .redirect =             fake_redirect,
-       .cow_metrics =          fake_cow_metrics,
-       .neigh_lookup =         fake_neigh_lookup,
-       .mtu =                  fake_mtu,
-};
-
-/*
- * Initialize bogus route table used to keep netfilter happy.
- * Currently, we fill in the PMTU entry because netfilter
- * refragmentation needs it, and the rt_flags entry because
- * ipt_REJECT needs it.  Future netfilter modules might
- * require us to fill additional fields.
- */
-static const u32 br_dst_default_metrics[RTAX_MAX] = {
-       [RTAX_MTU - 1] = 1500,
-};
-
-void br_netfilter_rtable_init(struct net_bridge *br)
-{
-       struct rtable *rt = &br->fake_rtable;
-
-       atomic_set(&rt->dst.__refcnt, 1);
-       rt->dst.dev = br->dev;
-       rt->dst.path = &rt->dst;
-       dst_init_metrics(&rt->dst, br_dst_default_metrics, true);
-       rt->dst.flags   = DST_NOXFRM | DST_FAKE_RTABLE;
-       rt->dst.ops = &fake_dst_ops;
-}
-
 static inline struct rtable *bridge_parent_rtable(const struct net_device *dev)
 {
        struct net_bridge_port *port;
 };
 #endif
 
-int __init br_netfilter_init(void)
+static int __init br_netfilter_init(void)
 {
        int ret;
 
-       ret = dst_entries_init(&fake_dst_ops);
+       ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
        if (ret < 0)
                return ret;
 
-       ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
-       if (ret < 0) {
-               dst_entries_destroy(&fake_dst_ops);
-               return ret;
-       }
 #ifdef CONFIG_SYSCTL
        brnf_sysctl_header = register_net_sysctl(&init_net, "net/bridge", brnf_table);
        if (brnf_sysctl_header == NULL) {
                printk(KERN_WARNING
                       "br_netfilter: can't register to sysctl.\n");
-               nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
-               dst_entries_destroy(&fake_dst_ops);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto err1;
        }
 #endif
        printk(KERN_NOTICE "Bridge firewalling registered\n");
        return 0;
+err1:
+       nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
+       return ret;
 }
 
-void br_netfilter_fini(void)
+static void __exit br_netfilter_fini(void)
 {
        nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
 #ifdef CONFIG_SYSCTL
        unregister_net_sysctl_table(brnf_sysctl_header);
 #endif
-       dst_entries_destroy(&fake_dst_ops);
 }
+
+module_init(br_netfilter_init);
+module_exit(br_netfilter_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lennert Buytenhek <buytenh@gnu.org>");
+MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
+MODULE_DESCRIPTION("Linux ethernet netfilter firewall bridge");
 
        return err;
 }
 
-void __exit br_netlink_fini(void)
+void br_netlink_fini(void)
 {
        br_mdb_uninit();
        rtnl_af_unregister(&br_af_ops);
 
--- /dev/null
+/*
+ *     Handle firewalling core
+ *     Linux ethernet bridge
+ *
+ *     Authors:
+ *     Lennert Buytenhek               <buytenh@gnu.org>
+ *     Bart De Schuymer                <bdschuym@pandora.be>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     Lennert dedicates this file to Kerstin Wurdinger.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/in_route.h>
+#include <linux/inetdevice.h>
+#include <net/route.h>
+
+#include "br_private.h"
+#ifdef CONFIG_SYSCTL
+#include <linux/sysctl.h>
+#endif
+
+static void fake_update_pmtu(struct dst_entry *dst, struct sock *sk,
+                            struct sk_buff *skb, u32 mtu)
+{
+}
+
+static void fake_redirect(struct dst_entry *dst, struct sock *sk,
+                         struct sk_buff *skb)
+{
+}
+
+static u32 *fake_cow_metrics(struct dst_entry *dst, unsigned long old)
+{
+       return NULL;
+}
+
+static struct neighbour *fake_neigh_lookup(const struct dst_entry *dst,
+                                          struct sk_buff *skb,
+                                          const void *daddr)
+{
+       return NULL;
+}
+
+static unsigned int fake_mtu(const struct dst_entry *dst)
+{
+       return dst->dev->mtu;
+}
+
+static struct dst_ops fake_dst_ops = {
+       .family         = AF_INET,
+       .protocol       = cpu_to_be16(ETH_P_IP),
+       .update_pmtu    = fake_update_pmtu,
+       .redirect       = fake_redirect,
+       .cow_metrics    = fake_cow_metrics,
+       .neigh_lookup   = fake_neigh_lookup,
+       .mtu            = fake_mtu,
+};
+
+/*
+ * Initialize bogus route table used to keep netfilter happy.
+ * Currently, we fill in the PMTU entry because netfilter
+ * refragmentation needs it, and the rt_flags entry because
+ * ipt_REJECT needs it.  Future netfilter modules might
+ * require us to fill additional fields.
+ */
+static const u32 br_dst_default_metrics[RTAX_MAX] = {
+       [RTAX_MTU - 1] = 1500,
+};
+
+void br_netfilter_rtable_init(struct net_bridge *br)
+{
+       struct rtable *rt = &br->fake_rtable;
+
+       atomic_set(&rt->dst.__refcnt, 1);
+       rt->dst.dev = br->dev;
+       rt->dst.path = &rt->dst;
+       dst_init_metrics(&rt->dst, br_dst_default_metrics, true);
+       rt->dst.flags   = DST_NOXFRM | DST_FAKE_RTABLE;
+       rt->dst.ops = &fake_dst_ops;
+}
+
+int __init br_nf_core_init(void)
+{
+       return dst_entries_init(&fake_dst_ops);
+}
+
+void br_nf_core_fini(void)
+{
+       dst_entries_destroy(&fake_dst_ops);
+}
 
        struct pcpu_sw_netstats         __percpu *stats;
        spinlock_t                      hash_lock;
        struct hlist_head               hash[BR_HASH_SIZE];
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        struct rtable                   fake_rtable;
        bool                            nf_call_iptables;
        bool                            nf_call_ip6tables;
 #endif
 
 /* br_netfilter.c */
-#ifdef CONFIG_BRIDGE_NETFILTER
-int br_netfilter_init(void);
-void br_netfilter_fini(void);
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+int br_nf_core_init(void);
+void br_nf_core_fini(void);
 void br_netfilter_rtable_init(struct net_bridge *);
 #else
-#define br_netfilter_init()    (0)
-#define br_netfilter_fini()    do { } while (0)
+static inline int br_nf_core_init(void) { return 0; }
+static inline void br_nf_core_fini(void) {}
 #define br_netfilter_rtable_init(x)
 #endif
 
 
 }
 static DEVICE_ATTR_RW(multicast_startup_query_interval);
 #endif
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
 static ssize_t nf_call_iptables_show(
        struct device *d, struct device_attribute *attr, char *buf)
 {
        &dev_attr_multicast_query_response_interval.attr,
        &dev_attr_multicast_startup_query_interval.attr,
 #endif
-#ifdef CONFIG_BRIDGE_NETFILTER
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        &dev_attr_nf_call_iptables.attr,
        &dev_attr_nf_call_ip6tables.attr,
        &dev_attr_nf_call_arptables.attr,