diff options
Diffstat (limited to 'net/bridge/br_input.c')
-rw-r--r-- | net/bridge/br_input.c | 28 |
1 files changed, 25 insertions, 3 deletions
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 4b34207419b1..480330151898 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/etherdevice.h> | 17 | #include <linux/etherdevice.h> |
18 | #include <linux/netfilter_bridge.h> | 18 | #include <linux/netfilter_bridge.h> |
19 | #include <linux/export.h> | 19 | #include <linux/export.h> |
20 | #include <linux/rculist.h> | ||
20 | #include "br_private.h" | 21 | #include "br_private.h" |
21 | 22 | ||
22 | /* Hook for brouter */ | 23 | /* Hook for brouter */ |
@@ -34,6 +35,20 @@ static int br_pass_frame_up(struct sk_buff *skb) | |||
34 | brstats->rx_bytes += skb->len; | 35 | brstats->rx_bytes += skb->len; |
35 | u64_stats_update_end(&brstats->syncp); | 36 | u64_stats_update_end(&brstats->syncp); |
36 | 37 | ||
38 | /* Bridge is just like any other port. Make sure the | ||
39 | * packet is allowed except in promisc modue when someone | ||
40 | * may be running packet capture. | ||
41 | */ | ||
42 | if (!(brdev->flags & IFF_PROMISC) && | ||
43 | !br_allowed_egress(br, br_get_vlan_info(br), skb)) { | ||
44 | kfree_skb(skb); | ||
45 | return NET_RX_DROP; | ||
46 | } | ||
47 | |||
48 | skb = br_handle_vlan(br, br_get_vlan_info(br), skb); | ||
49 | if (!skb) | ||
50 | return NET_RX_DROP; | ||
51 | |||
37 | indev = skb->dev; | 52 | indev = skb->dev; |
38 | skb->dev = brdev; | 53 | skb->dev = brdev; |
39 | 54 | ||
@@ -50,13 +65,17 @@ int br_handle_frame_finish(struct sk_buff *skb) | |||
50 | struct net_bridge_fdb_entry *dst; | 65 | struct net_bridge_fdb_entry *dst; |
51 | struct net_bridge_mdb_entry *mdst; | 66 | struct net_bridge_mdb_entry *mdst; |
52 | struct sk_buff *skb2; | 67 | struct sk_buff *skb2; |
68 | u16 vid = 0; | ||
53 | 69 | ||
54 | if (!p || p->state == BR_STATE_DISABLED) | 70 | if (!p || p->state == BR_STATE_DISABLED) |
55 | goto drop; | 71 | goto drop; |
56 | 72 | ||
73 | if (!br_allowed_ingress(p->br, nbp_get_vlan_info(p), skb, &vid)) | ||
74 | goto drop; | ||
75 | |||
57 | /* insert into forwarding database after filtering to avoid spoofing */ | 76 | /* insert into forwarding database after filtering to avoid spoofing */ |
58 | br = p->br; | 77 | br = p->br; |
59 | br_fdb_update(br, p, eth_hdr(skb)->h_source); | 78 | br_fdb_update(br, p, eth_hdr(skb)->h_source, vid); |
60 | 79 | ||
61 | if (!is_broadcast_ether_addr(dest) && is_multicast_ether_addr(dest) && | 80 | if (!is_broadcast_ether_addr(dest) && is_multicast_ether_addr(dest) && |
62 | br_multicast_rcv(br, p, skb)) | 81 | br_multicast_rcv(br, p, skb)) |
@@ -91,7 +110,8 @@ int br_handle_frame_finish(struct sk_buff *skb) | |||
91 | skb2 = skb; | 110 | skb2 = skb; |
92 | 111 | ||
93 | br->dev->stats.multicast++; | 112 | br->dev->stats.multicast++; |
94 | } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) { | 113 | } else if ((dst = __br_fdb_get(br, dest, vid)) && |
114 | dst->is_local) { | ||
95 | skb2 = skb; | 115 | skb2 = skb; |
96 | /* Do not forward the packet since it's local. */ | 116 | /* Do not forward the packet since it's local. */ |
97 | skb = NULL; | 117 | skb = NULL; |
@@ -119,8 +139,10 @@ drop: | |||
119 | static int br_handle_local_finish(struct sk_buff *skb) | 139 | static int br_handle_local_finish(struct sk_buff *skb) |
120 | { | 140 | { |
121 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); | 141 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); |
142 | u16 vid = 0; | ||
122 | 143 | ||
123 | br_fdb_update(p->br, p, eth_hdr(skb)->h_source); | 144 | br_vlan_get_tag(skb, &vid); |
145 | br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid); | ||
124 | return 0; /* process further */ | 146 | return 0; /* process further */ |
125 | } | 147 | } |
126 | 148 | ||