aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/bridge/br_forward.c33
-rw-r--r--net/bridge/br_input.c5
-rw-r--r--net/bridge/br_private.h3
3 files changed, 25 insertions, 16 deletions
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index bc1704ac6cd9..6cd50c6e57cf 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -105,8 +105,9 @@ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
105 105
106/* called under bridge lock */ 106/* called under bridge lock */
107static void br_flood(struct net_bridge *br, struct sk_buff *skb, 107static void br_flood(struct net_bridge *br, struct sk_buff *skb,
108 void (*__packet_hook)(const struct net_bridge_port *p, 108 struct sk_buff *skb0,
109 struct sk_buff *skb)) 109 void (*__packet_hook)(const struct net_bridge_port *p,
110 struct sk_buff *skb))
110{ 111{
111 struct net_bridge_port *p; 112 struct net_bridge_port *p;
112 struct net_bridge_port *prev; 113 struct net_bridge_port *prev;
@@ -120,8 +121,7 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
120 121
121 if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { 122 if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
122 br->dev->stats.tx_dropped++; 123 br->dev->stats.tx_dropped++;
123 kfree_skb(skb); 124 goto out;
124 return;
125 } 125 }
126 126
127 __packet_hook(prev, skb2); 127 __packet_hook(prev, skb2);
@@ -131,23 +131,34 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
131 } 131 }
132 } 132 }
133 133
134 if (prev != NULL) { 134 if (!prev)
135 __packet_hook(prev, skb); 135 goto out;
136 return; 136
137 if (skb0) {
138 skb = skb_clone(skb, GFP_ATOMIC);
139 if (!skb) {
140 br->dev->stats.tx_dropped++;
141 goto out;
142 }
137 } 143 }
144 __packet_hook(prev, skb);
145 return;
138 146
139 kfree_skb(skb); 147out:
148 if (!skb0)
149 kfree_skb(skb);
140} 150}
141 151
142 152
143/* called with rcu_read_lock */ 153/* called with rcu_read_lock */
144void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb) 154void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb)
145{ 155{
146 br_flood(br, skb, __br_deliver); 156 br_flood(br, skb, NULL, __br_deliver);
147} 157}
148 158
149/* called under bridge lock */ 159/* called under bridge lock */
150void br_flood_forward(struct net_bridge *br, struct sk_buff *skb) 160void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
161 struct sk_buff *skb2)
151{ 162{
152 br_flood(br, skb, __br_forward); 163 br_flood(br, skb, skb2, __br_forward);
153} 164}
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index be5ab8df6661..edfdaef44296 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -72,14 +72,11 @@ int br_handle_frame_finish(struct sk_buff *skb)
72 skb = NULL; 72 skb = NULL;
73 } 73 }
74 74
75 if (skb2 == skb)
76 skb2 = skb_clone(skb, GFP_ATOMIC);
77
78 if (skb) { 75 if (skb) {
79 if (dst) 76 if (dst)
80 br_forward(dst->dst, skb); 77 br_forward(dst->dst, skb);
81 else 78 else
82 br_flood_forward(br, skb); 79 br_flood_forward(br, skb, skb2);
83 } 80 }
84 81
85 if (skb2) 82 if (skb2)
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 16513793156e..fad5a2669d34 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -180,7 +180,8 @@ extern void br_forward(const struct net_bridge_port *to,
180 struct sk_buff *skb); 180 struct sk_buff *skb);
181extern int br_forward_finish(struct sk_buff *skb); 181extern int br_forward_finish(struct sk_buff *skb);
182extern void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb); 182extern void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb);
183extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb); 183extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
184 struct sk_buff *skb2);
184 185
185/* br_if.c */ 186/* br_if.c */
186extern void br_port_carrier_check(struct net_bridge_port *p); 187extern void br_port_carrier_check(struct net_bridge_port *p);