aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavem <davem>2001-12-24 04:50:20 +0000
committerdavem <davem>2001-12-24 04:50:20 +0000
commit3ffc1620675cfd960399871aae77f596cfbde71b (patch)
tree1741e6dd9d47faa151d0bf449f4fee135b8592e7
parent46bc6e8d456c43c1916cc4750cc6de3383f9e523 (diff)
downloadnetdev-vger-cvs-3ffc1620675cfd960399871aae77f596cfbde71b.tar.gz
Port state handling fixes to br input processing.
From Lennert Buytenhek.
-rw-r--r--net/bridge/br_input.c125
1 files changed, 67 insertions, 58 deletions
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 1f111a59c..0b37a1a89 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_input.c,v 1.9 2001-08-14 22:05:57 davem Exp $
+ * $Id: br_input.c,v 1.10 2001-12-24 04:50:20 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -46,7 +46,7 @@ static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
br_pass_frame_up_finish);
}
-static void __br_handle_frame(struct sk_buff *skb)
+static int br_handle_frame_finish(struct sk_buff *skb)
{
struct net_bridge *br;
unsigned char *dest;
@@ -57,103 +57,112 @@ static void __br_handle_frame(struct sk_buff *skb)
dest = skb->mac.ethernet->h_dest;
p = skb->dev->br_port;
- br = p->br;
- passedup = 0;
+ if (p == NULL)
+ goto err_nolock;
- if (!(br->dev.flags & IFF_UP) ||
- p->state == BR_STATE_DISABLED)
- goto freeandout;
+ br = p->br;
+ read_lock(&br->lock);
+ if (skb->dev->br_port == NULL)
+ goto err;
+ passedup = 0;
if (br->dev.flags & IFF_PROMISC) {
struct sk_buff *skb2;
skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2) {
+ if (skb2 != NULL) {
passedup = 1;
br_pass_frame_up(br, skb2);
}
}
- if (skb->mac.ethernet->h_source[0] & 1)
- goto freeandout;
-
- if (!passedup &&
- (dest[0] & 1) &&
- (br->dev.flags & IFF_ALLMULTI || br->dev.mc_list != NULL)) {
- struct sk_buff *skb2;
-
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2) {
- passedup = 1;
- br_pass_frame_up(br, skb2);
- }
- }
-
- if (br->stp_enabled &&
- !memcmp(dest, bridge_ula, 5) &&
- !(dest[5] & 0xF0))
- goto handle_special_frame;
-
- if (p->state == BR_STATE_LEARNING ||
- p->state == BR_STATE_FORWARDING)
- br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0);
-
- if (p->state != BR_STATE_FORWARDING)
- goto freeandout;
-
if (dest[0] & 1) {
- br_flood_forward(br, skb, 1);
+ br_flood_forward(br, skb, !passedup);
if (!passedup)
br_pass_frame_up(br, skb);
- else
- kfree_skb(skb);
- return;
+ goto out;
}
dst = br_fdb_get(br, dest);
-
if (dst != NULL && dst->is_local) {
if (!passedup)
br_pass_frame_up(br, skb);
else
kfree_skb(skb);
br_fdb_put(dst);
- return;
+ goto out;
}
if (dst != NULL) {
br_forward(dst->dst, skb);
br_fdb_put(dst);
- return;
+ goto out;
}
br_flood_forward(br, skb, 0);
- return;
- handle_special_frame:
- if (!dest[5]) {
- br_stp_handle_bpdu(skb);
- return;
- }
+out:
+ read_unlock(&br->lock);
+ return 0;
- freeandout:
+err:
+ read_unlock(&br->lock);
+err_nolock:
kfree_skb(skb);
+ return 0;
}
-static int br_handle_frame_finish(struct sk_buff *skb)
+void br_handle_frame(struct sk_buff *skb)
{
struct net_bridge *br;
+ unsigned char *dest;
+ struct net_bridge_port *p;
- br = skb->dev->br_port->br;
+ dest = skb->mac.ethernet->h_dest;
+
+ p = skb->dev->br_port;
+ if (p == NULL)
+ goto err_nolock;
+
+ br = p->br;
read_lock(&br->lock);
- __br_handle_frame(skb);
- read_unlock(&br->lock);
+ if (skb->dev->br_port == NULL)
+ goto err;
- return 0;
-}
+ if (!(br->dev.flags & IFF_UP) ||
+ p->state == BR_STATE_DISABLED)
+ goto err;
-void br_handle_frame(struct sk_buff *skb)
-{
- NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+ if (skb->mac.ethernet->h_source[0] & 1)
+ goto err;
+
+ if (p->state == BR_STATE_LEARNING ||
+ p->state == BR_STATE_FORWARDING)
+ br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0);
+
+ if (br->stp_enabled &&
+ !memcmp(dest, bridge_ula, 5) &&
+ !(dest[5] & 0xF0))
+ goto handle_special_frame;
+
+ if (p->state == BR_STATE_FORWARDING) {
+ NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
br_handle_frame_finish);
+ read_unlock(&br->lock);
+ return;
+ }
+
+err:
+ read_unlock(&br->lock);
+err_nolock:
+ kfree_skb(skb);
+ return;
+
+handle_special_frame:
+ if (!dest[5]) {
+ br_stp_handle_bpdu(skb);
+ return;
+ }
+
+ kfree_skb(skb);
}