net: Add optional SKB arg to dst_ops->neigh_lookup().
[firefly-linux-kernel-4.4.55.git] / net / bridge / br_netfilter.c
index d7f49b63ab0fd17b82828f60278b5f8a99664a1d..4378775432b69302e2063f31668a6fb2a8c4a81e 100644 (file)
@@ -54,12 +54,14 @@ static int brnf_call_ip6tables __read_mostly = 1;
 static int brnf_call_arptables __read_mostly = 1;
 static int brnf_filter_vlan_tagged __read_mostly = 0;
 static int brnf_filter_pppoe_tagged __read_mostly = 0;
+static int brnf_pass_vlan_indev __read_mostly = 0;
 #else
 #define brnf_call_iptables 1
 #define brnf_call_ip6tables 1
 #define brnf_call_arptables 1
 #define brnf_filter_vlan_tagged 0
 #define brnf_filter_pppoe_tagged 0
+#define brnf_pass_vlan_indev 0
 #endif
 
 #define IS_IP(skb) \
@@ -118,7 +120,9 @@ 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, const void *daddr)
+static struct neighbour *fake_neigh_lookup(const struct dst_entry *dst,
+                                          struct sk_buff *skb,
+                                          const void *daddr)
 {
        return NULL;
 }
@@ -503,6 +507,19 @@ bridged_dnat:
        return 0;
 }
 
+static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct net_device *dev)
+{
+       struct net_device *vlan, *br;
+
+       br = bridge_parent(dev);
+       if (brnf_pass_vlan_indev == 0 || !vlan_tx_tag_present(skb))
+               return br;
+
+       vlan = __vlan_find_dev_deep(br, vlan_tx_tag_get(skb) & VLAN_VID_MASK);
+
+       return vlan ? vlan : br;
+}
+
 /* Some common code for IPv4/IPv6 */
 static struct net_device *setup_pre_routing(struct sk_buff *skb)
 {
@@ -515,7 +532,7 @@ static struct net_device *setup_pre_routing(struct sk_buff *skb)
 
        nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING;
        nf_bridge->physindev = skb->dev;
-       skb->dev = bridge_parent(skb->dev);
+       skb->dev = brnf_get_logical_dev(skb, skb->dev);
        if (skb->protocol == htons(ETH_P_8021Q))
                nf_bridge->mask |= BRNF_8021Q;
        else if (skb->protocol == htons(ETH_P_PPP_SES))
@@ -543,7 +560,7 @@ static int check_hbh_len(struct sk_buff *skb)
                int optlen = nh[off + 1] + 2;
 
                switch (nh[off]) {
-               case IPV6_TLV_PAD0:
+               case IPV6_TLV_PAD1:
                        optlen = 1;
                        break;
 
@@ -749,9 +766,9 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
                return NF_DROP;
 
        if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
-               pf = PF_INET;
+               pf = NFPROTO_IPV4;
        else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
-               pf = PF_INET6;
+               pf = NFPROTO_IPV6;
        else
                return NF_ACCEPT;
 
@@ -763,18 +780,18 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
                nf_bridge->mask |= BRNF_PKT_TYPE;
        }
 
-       if (pf == PF_INET && br_parse_ip_options(skb))
+       if (pf == NFPROTO_IPV4 && br_parse_ip_options(skb))
                return NF_DROP;
 
        /* The physdev module checks on this */
        nf_bridge->mask |= BRNF_BRIDGED;
        nf_bridge->physoutdev = skb->dev;
-       if (pf == PF_INET)
+       if (pf == NFPROTO_IPV4)
                skb->protocol = htons(ETH_P_IP);
        else
                skb->protocol = htons(ETH_P_IPV6);
 
-       NF_HOOK(pf, NF_INET_FORWARD, skb, bridge_parent(in), parent,
+       NF_HOOK(pf, NF_INET_FORWARD, skb, brnf_get_logical_dev(skb, in), parent,
                br_nf_forward_finish);
 
        return NF_STOLEN;
@@ -856,9 +873,9 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
                return NF_DROP;
 
        if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
-               pf = PF_INET;
+               pf = NFPROTO_IPV4;
        else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
-               pf = PF_INET6;
+               pf = NFPROTO_IPV6;
        else
                return NF_ACCEPT;
 
@@ -871,7 +888,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
 
        nf_bridge_pull_encap_header(skb);
        nf_bridge_save_header(skb);
-       if (pf == PF_INET)
+       if (pf == NFPROTO_IPV4)
                skb->protocol = htons(ETH_P_IP);
        else
                skb->protocol = htons(ETH_P_IPV6);
@@ -904,49 +921,49 @@ static struct nf_hook_ops br_nf_ops[] __read_mostly = {
        {
                .hook = br_nf_pre_routing,
                .owner = THIS_MODULE,
-               .pf = PF_BRIDGE,
+               .pf = NFPROTO_BRIDGE,
                .hooknum = NF_BR_PRE_ROUTING,
                .priority = NF_BR_PRI_BRNF,
        },
        {
                .hook = br_nf_local_in,
                .owner = THIS_MODULE,
-               .pf = PF_BRIDGE,
+               .pf = NFPROTO_BRIDGE,
                .hooknum = NF_BR_LOCAL_IN,
                .priority = NF_BR_PRI_BRNF,
        },
        {
                .hook = br_nf_forward_ip,
                .owner = THIS_MODULE,
-               .pf = PF_BRIDGE,
+               .pf = NFPROTO_BRIDGE,
                .hooknum = NF_BR_FORWARD,
                .priority = NF_BR_PRI_BRNF - 1,
        },
        {
                .hook = br_nf_forward_arp,
                .owner = THIS_MODULE,
-               .pf = PF_BRIDGE,
+               .pf = NFPROTO_BRIDGE,
                .hooknum = NF_BR_FORWARD,
                .priority = NF_BR_PRI_BRNF,
        },
        {
                .hook = br_nf_post_routing,
                .owner = THIS_MODULE,
-               .pf = PF_BRIDGE,
+               .pf = NFPROTO_BRIDGE,
                .hooknum = NF_BR_POST_ROUTING,
                .priority = NF_BR_PRI_LAST,
        },
        {
                .hook = ip_sabotage_in,
                .owner = THIS_MODULE,
-               .pf = PF_INET,
+               .pf = NFPROTO_IPV4,
                .hooknum = NF_INET_PRE_ROUTING,
                .priority = NF_IP_PRI_FIRST,
        },
        {
                .hook = ip_sabotage_in,
                .owner = THIS_MODULE,
-               .pf = PF_INET6,
+               .pf = NFPROTO_IPV6,
                .hooknum = NF_INET_PRE_ROUTING,
                .priority = NF_IP6_PRI_FIRST,
        },
@@ -1002,12 +1019,13 @@ static ctl_table brnf_table[] = {
                .mode           = 0644,
                .proc_handler   = brnf_sysctl_call_tables,
        },
-       { }
-};
-
-static struct ctl_path brnf_path[] = {
-       { .procname = "net", },
-       { .procname = "bridge", },
+       {
+               .procname       = "bridge-nf-pass-vlan-input-dev",
+               .data           = &brnf_pass_vlan_indev,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = brnf_sysctl_call_tables,
+       },
        { }
 };
 #endif
@@ -1026,7 +1044,7 @@ int __init br_netfilter_init(void)
                return ret;
        }
 #ifdef CONFIG_SYSCTL
-       brnf_sysctl_header = register_sysctl_paths(brnf_path, brnf_table);
+       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");
@@ -1043,7 +1061,7 @@ void br_netfilter_fini(void)
 {
        nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
 #ifdef CONFIG_SYSCTL
-       unregister_sysctl_table(brnf_sysctl_header);
+       unregister_net_sysctl_table(brnf_sysctl_header);
 #endif
        dst_entries_destroy(&fake_dst_ops);
 }