From 0de6d5c4c2f7fabb1621b219556ed8da5c566f7f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 27 Feb 2010 19:41:43 +0000 Subject: [PATCH] --- yaml --- r: 184566 b: refs/heads/master c: 025d89c27f54c69cd0e51666d88aada33666bb6c h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/net/bridge/br_forward.c | 69 +++++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/[refs] b/[refs] index aec16358694c..a3cb086fbd09 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 6088a539d8d1666dca6979b5759bf966ee9124ef +refs/heads/master: 025d89c27f54c69cd0e51666d88aada33666bb6c diff --git a/trunk/net/bridge/br_forward.c b/trunk/net/bridge/br_forward.c index 2e1cb434f6cd..86cd0712d63e 100644 --- a/trunk/net/bridge/br_forward.c +++ b/trunk/net/bridge/br_forward.c @@ -11,6 +11,7 @@ * 2 of the License, or (at your option) any later version. */ +#include #include #include #include @@ -103,6 +104,44 @@ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb) kfree_skb(skb); } +static int deliver_clone(struct net_bridge_port *prev, struct sk_buff *skb, + void (*__packet_hook)(const struct net_bridge_port *p, + struct sk_buff *skb)) +{ + skb = skb_clone(skb, GFP_ATOMIC); + if (!skb) { + struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev; + + dev->stats.tx_dropped++; + return -ENOMEM; + } + + __packet_hook(prev, skb); + return 0; +} + +static struct net_bridge_port *maybe_deliver( + struct net_bridge_port *prev, struct net_bridge_port *p, + struct sk_buff *skb, + void (*__packet_hook)(const struct net_bridge_port *p, + struct sk_buff *skb)) +{ + int err; + + if (!should_deliver(p, skb)) + return prev; + + if (!prev) + goto out; + + err = deliver_clone(prev, skb, __packet_hook); + if (err) + return ERR_PTR(err); + +out: + return p; +} + /* called under bridge lock */ static void br_flood(struct net_bridge *br, struct sk_buff *skb, struct sk_buff *skb0, @@ -111,38 +150,22 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb, { struct net_bridge_port *p; struct net_bridge_port *prev; - struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev; prev = NULL; list_for_each_entry_rcu(p, &br->port_list, list) { - if (should_deliver(p, skb)) { - if (prev != NULL) { - struct sk_buff *skb2; - - if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { - dev->stats.tx_dropped++; - goto out; - } - - __packet_hook(prev, skb2); - } - - prev = p; - } + prev = maybe_deliver(prev, p, skb, __packet_hook); + if (IS_ERR(prev)) + goto out; } if (!prev) goto out; - if (skb0) { - skb = skb_clone(skb, GFP_ATOMIC); - if (!skb) { - dev->stats.tx_dropped++; - goto out; - } - } - __packet_hook(prev, skb); + if (skb0) + deliver_clone(prev, skb, __packet_hook); + else + __packet_hook(prev, skb); return; out: