diff options
author | davem <davem> | 2001-12-24 04:50:20 +0000 |
---|---|---|
committer | davem <davem> | 2001-12-24 04:50:20 +0000 |
commit | 3ffc1620675cfd960399871aae77f596cfbde71b (patch) | |
tree | 1741e6dd9d47faa151d0bf449f4fee135b8592e7 | |
parent | 46bc6e8d456c43c1916cc4750cc6de3383f9e523 (diff) | |
download | netdev-vger-cvs-3ffc1620675cfd960399871aae77f596cfbde71b.tar.gz |
Port state handling fixes to br input processing.
From Lennert Buytenhek.
-rw-r--r-- | net/bridge/br_input.c | 125 |
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); } |