--- zzzz-none-000/linux-2.6.32.61/net/bridge/br_stp_bpdu.c 2013-06-10 09:43:48.000000000 +0000 +++ ar10-7272-687/linux-2.6.32.61/net/bridge/br_stp_bpdu.c 2014-08-12 13:03:17.000000000 +0000 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -51,7 +52,9 @@ llc_mac_hdr_init(skb, p->dev->dev_addr, p->br->group_addr); - NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, + skb_reset_mac_header(skb); + + NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, dev_queue_xmit); } @@ -132,19 +135,16 @@ /* * Called from llc. * - * NO locks, but rcu_read_lock (preempt_disabled) + * NO locks, but rcu_read_lock */ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, struct net_device *dev) { const unsigned char *dest = eth_hdr(skb)->h_dest; - struct net_bridge_port *p = rcu_dereference(dev->br_port); + struct net_bridge_port *p; struct net_bridge *br; const unsigned char *buf; - if (!p) - goto err; - if (!pskb_may_pull(skb, 4)) goto err; @@ -153,6 +153,10 @@ if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0) goto err; + p = br_port_get_check_rcu(dev); + if (!p) + goto err; + br = p->br; spin_lock(&br->lock); @@ -165,9 +169,16 @@ if (p->state == BR_STATE_DISABLED) goto out; - if (compare_ether_addr(dest, br->group_addr) != 0) + if (!ether_addr_equal(dest, br->group_addr)) goto out; + if (p->flags & BR_BPDU_GUARD) { + br_notice(br, "BPDU received on blocked port %u(%s)\n", + (unsigned int) p->port_no, p->dev->name); + br_stp_disable_port(p); + goto out; + } + buf = skb_pull(skb, 3); if (buf[0] == BPDU_TYPE_CONFIG) { @@ -208,10 +219,19 @@ bpdu.hello_time = br_get_ticks(buf+28); bpdu.forward_delay = br_get_ticks(buf+30); - br_received_config_bpdu(p, &bpdu); - } + if (bpdu.message_age > bpdu.max_age) { + if (net_ratelimit()) + br_notice(p->br, + "port %u config from %pM" + " (message_age %ul > max_age %ul)\n", + p->port_no, + eth_hdr(skb)->h_source, + bpdu.message_age, bpdu.max_age); + goto out; + } - else if (buf[0] == BPDU_TYPE_TCN) { + br_received_config_bpdu(p, &bpdu); + } else if (buf[0] == BPDU_TYPE_TCN) { br_received_tcn_bpdu(p); } out: