]> Pileus Git - ~andy/linux/blobdiff - net/bridge/br_input.c
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[~andy/linux] / net / bridge / br_input.c
index 4b34207419b1cfbe39ca54321cf9087101bab155..480330151898486eee3a42382c28f327021d111b 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/etherdevice.h>
 #include <linux/netfilter_bridge.h>
 #include <linux/export.h>
+#include <linux/rculist.h>
 #include "br_private.h"
 
 /* Hook for brouter */
@@ -34,6 +35,20 @@ static int br_pass_frame_up(struct sk_buff *skb)
        brstats->rx_bytes += skb->len;
        u64_stats_update_end(&brstats->syncp);
 
+       /* Bridge is just like any other port.  Make sure the
+        * packet is allowed except in promisc modue when someone
+        * may be running packet capture.
+        */
+       if (!(brdev->flags & IFF_PROMISC) &&
+           !br_allowed_egress(br, br_get_vlan_info(br), skb)) {
+               kfree_skb(skb);
+               return NET_RX_DROP;
+       }
+
+       skb = br_handle_vlan(br, br_get_vlan_info(br), skb);
+       if (!skb)
+               return NET_RX_DROP;
+
        indev = skb->dev;
        skb->dev = brdev;
 
@@ -50,13 +65,17 @@ int br_handle_frame_finish(struct sk_buff *skb)
        struct net_bridge_fdb_entry *dst;
        struct net_bridge_mdb_entry *mdst;
        struct sk_buff *skb2;
+       u16 vid = 0;
 
        if (!p || p->state == BR_STATE_DISABLED)
                goto drop;
 
+       if (!br_allowed_ingress(p->br, nbp_get_vlan_info(p), skb, &vid))
+               goto drop;
+
        /* insert into forwarding database after filtering to avoid spoofing */
        br = p->br;
-       br_fdb_update(br, p, eth_hdr(skb)->h_source);
+       br_fdb_update(br, p, eth_hdr(skb)->h_source, vid);
 
        if (!is_broadcast_ether_addr(dest) && is_multicast_ether_addr(dest) &&
            br_multicast_rcv(br, p, skb))
@@ -91,7 +110,8 @@ int br_handle_frame_finish(struct sk_buff *skb)
                        skb2 = skb;
 
                br->dev->stats.multicast++;
-       } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) {
+       } else if ((dst = __br_fdb_get(br, dest, vid)) &&
+                       dst->is_local) {
                skb2 = skb;
                /* Do not forward the packet since it's local. */
                skb = NULL;
@@ -119,8 +139,10 @@ drop:
 static int br_handle_local_finish(struct sk_buff *skb)
 {
        struct net_bridge_port *p = br_port_get_rcu(skb->dev);
+       u16 vid = 0;
 
-       br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
+       br_vlan_get_tag(skb, &vid);
+       br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid);
        return 0;        /* process further */
 }