aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge/br_input.c')
-rw-r--r--net/bridge/br_input.c42
1 files changed, 29 insertions, 13 deletions
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 5ee1a3682bf2..a82dde2d2ead 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -11,6 +11,7 @@
11 * 2 of the License, or (at your option) any later version. 11 * 2 of the License, or (at your option) any later version.
12 */ 12 */
13 13
14#include <linux/slab.h>
14#include <linux/kernel.h> 15#include <linux/kernel.h>
15#include <linux/netdevice.h> 16#include <linux/netdevice.h>
16#include <linux/etherdevice.h> 17#include <linux/etherdevice.h>
@@ -20,9 +21,9 @@
20/* Bridge group multicast address 802.1d (pg 51). */ 21/* Bridge group multicast address 802.1d (pg 51). */
21const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; 22const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
22 23
23static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) 24static int br_pass_frame_up(struct sk_buff *skb)
24{ 25{
25 struct net_device *indev, *brdev = br->dev; 26 struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
26 27
27 brdev->stats.rx_packets++; 28 brdev->stats.rx_packets++;
28 brdev->stats.rx_bytes += skb->len; 29 brdev->stats.rx_bytes += skb->len;
@@ -30,8 +31,8 @@ static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
30 indev = skb->dev; 31 indev = skb->dev;
31 skb->dev = brdev; 32 skb->dev = brdev;
32 33
33 NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, 34 return NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
34 netif_receive_skb); 35 netif_receive_skb);
35} 36}
36 37
37/* note: already called with rcu_read_lock (preempt_disabled) */ 38/* note: already called with rcu_read_lock (preempt_disabled) */
@@ -41,6 +42,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
41 struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); 42 struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
42 struct net_bridge *br; 43 struct net_bridge *br;
43 struct net_bridge_fdb_entry *dst; 44 struct net_bridge_fdb_entry *dst;
45 struct net_bridge_mdb_entry *mdst;
44 struct sk_buff *skb2; 46 struct sk_buff *skb2;
45 47
46 if (!p || p->state == BR_STATE_DISABLED) 48 if (!p || p->state == BR_STATE_DISABLED)
@@ -50,9 +52,15 @@ int br_handle_frame_finish(struct sk_buff *skb)
50 br = p->br; 52 br = p->br;
51 br_fdb_update(br, p, eth_hdr(skb)->h_source); 53 br_fdb_update(br, p, eth_hdr(skb)->h_source);
52 54
55 if (is_multicast_ether_addr(dest) &&
56 br_multicast_rcv(br, p, skb))
57 goto drop;
58
53 if (p->state == BR_STATE_LEARNING) 59 if (p->state == BR_STATE_LEARNING)
54 goto drop; 60 goto drop;
55 61
62 BR_INPUT_SKB_CB(skb)->brdev = br->dev;
63
56 /* The packet skb2 goes to the local host (NULL to skip). */ 64 /* The packet skb2 goes to the local host (NULL to skip). */
57 skb2 = NULL; 65 skb2 = NULL;
58 66
@@ -62,27 +70,35 @@ int br_handle_frame_finish(struct sk_buff *skb)
62 dst = NULL; 70 dst = NULL;
63 71
64 if (is_multicast_ether_addr(dest)) { 72 if (is_multicast_ether_addr(dest)) {
73 mdst = br_mdb_get(br, skb);
74 if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) {
75 if ((mdst && !hlist_unhashed(&mdst->mglist)) ||
76 br_multicast_is_router(br))
77 skb2 = skb;
78 br_multicast_forward(mdst, skb, skb2);
79 skb = NULL;
80 if (!skb2)
81 goto out;
82 } else
83 skb2 = skb;
84
65 br->dev->stats.multicast++; 85 br->dev->stats.multicast++;
66 skb2 = skb;
67 } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) { 86 } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) {
68 skb2 = skb; 87 skb2 = skb;
69 /* Do not forward the packet since it's local. */ 88 /* Do not forward the packet since it's local. */
70 skb = NULL; 89 skb = NULL;
71 } 90 }
72 91
73 if (skb2 == skb)
74 skb2 = skb_clone(skb, GFP_ATOMIC);
75
76 if (skb2)
77 br_pass_frame_up(br, skb2);
78
79 if (skb) { 92 if (skb) {
80 if (dst) 93 if (dst)
81 br_forward(dst->dst, skb); 94 br_forward(dst->dst, skb, skb2);
82 else 95 else
83 br_flood_forward(br, skb); 96 br_flood_forward(br, skb, skb2);
84 } 97 }
85 98
99 if (skb2)
100 return br_pass_frame_up(skb2);
101
86out: 102out:
87 return 0; 103 return 0;
88drop: 104drop: