diff options
Diffstat (limited to 'net/bridge/br_input.c')
-rw-r--r-- | net/bridge/br_input.c | 48 |
1 files changed, 22 insertions, 26 deletions
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 6f468fc3357a..3a8a015c92e0 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -43,7 +43,7 @@ int br_handle_frame_finish(struct sk_buff *skb) | |||
43 | struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); | 43 | struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); |
44 | struct net_bridge *br; | 44 | struct net_bridge *br; |
45 | struct net_bridge_fdb_entry *dst; | 45 | struct net_bridge_fdb_entry *dst; |
46 | int passedup = 0; | 46 | struct sk_buff *skb2; |
47 | 47 | ||
48 | if (!p || p->state == BR_STATE_DISABLED) | 48 | if (!p || p->state == BR_STATE_DISABLED) |
49 | goto drop; | 49 | goto drop; |
@@ -55,39 +55,35 @@ int br_handle_frame_finish(struct sk_buff *skb) | |||
55 | if (p->state == BR_STATE_LEARNING) | 55 | if (p->state == BR_STATE_LEARNING) |
56 | goto drop; | 56 | goto drop; |
57 | 57 | ||
58 | if (br->dev->flags & IFF_PROMISC) { | 58 | /* The packet skb2 goes to the local host (NULL to skip). */ |
59 | struct sk_buff *skb2; | 59 | skb2 = NULL; |
60 | 60 | ||
61 | skb2 = skb_clone(skb, GFP_ATOMIC); | 61 | if (br->dev->flags & IFF_PROMISC) |
62 | if (skb2 != NULL) { | 62 | skb2 = skb; |
63 | passedup = 1; | 63 | |
64 | br_pass_frame_up(br, skb2); | 64 | dst = NULL; |
65 | } | ||
66 | } | ||
67 | 65 | ||
68 | if (is_multicast_ether_addr(dest)) { | 66 | if (is_multicast_ether_addr(dest)) { |
69 | br->statistics.multicast++; | 67 | br->statistics.multicast++; |
70 | br_flood_forward(br, skb, !passedup); | 68 | skb2 = skb; |
71 | if (!passedup) | 69 | } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) { |
72 | br_pass_frame_up(br, skb); | 70 | skb2 = skb; |
73 | goto out; | 71 | /* Do not forward the packet since it's local. */ |
72 | skb = NULL; | ||
74 | } | 73 | } |
75 | 74 | ||
76 | dst = __br_fdb_get(br, dest); | 75 | if (skb2 == skb) |
77 | if (dst != NULL && dst->is_local) { | 76 | skb2 = skb_clone(skb, GFP_ATOMIC); |
78 | if (!passedup) | ||
79 | br_pass_frame_up(br, skb); | ||
80 | else | ||
81 | kfree_skb(skb); | ||
82 | goto out; | ||
83 | } | ||
84 | 77 | ||
85 | if (dst != NULL) { | 78 | if (skb2) |
86 | br_forward(dst->dst, skb); | 79 | br_pass_frame_up(br, skb2); |
87 | goto out; | ||
88 | } | ||
89 | 80 | ||
90 | br_flood_forward(br, skb, 0); | 81 | if (skb) { |
82 | if (dst) | ||
83 | br_forward(dst->dst, skb); | ||
84 | else | ||
85 | br_flood_forward(br, skb); | ||
86 | } | ||
91 | 87 | ||
92 | out: | 88 | out: |
93 | return 0; | 89 | return 0; |