* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_stp.c,v 1.4 2000/06/19 10:13:35 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
+#include <linux/rculist.h>
#include "br_private.h"
#include "br_private_stp.h"
*/
#define MESSAGE_AGE_INCR ((HZ < 256) ? 1 : (HZ/256))
-static const char *br_port_state_names[] = {
- [BR_STATE_DISABLED] = "disabled",
+static const char *const br_port_state_names[] = {
+ [BR_STATE_DISABLED] = "disabled",
[BR_STATE_LISTENING] = "listening",
- [BR_STATE_LEARNING] = "learning",
- [BR_STATE_FORWARDING] = "forwarding",
+ [BR_STATE_LEARNING] = "learning",
+ [BR_STATE_FORWARDING] = "forwarding",
[BR_STATE_BLOCKING] = "blocking",
};
void br_log_state(const struct net_bridge_port *p)
{
pr_info("%s: port %d(%s) entering %s state\n",
- p->br->dev->name, p->port_no, p->dev->name,
+ p->br->dev->name, p->port_no, p->dev->name,
br_port_state_names[p->state]);
}
}
/* called under bridge lock */
-static int br_should_become_root_port(const struct net_bridge_port *p,
+static int br_should_become_root_port(const struct net_bridge_port *p,
u16 root_port)
{
struct net_bridge *br;
br_send_config_bpdu(p, &bpdu);
p->topology_change_ack = 0;
p->config_pending = 0;
- mod_timer(&p->hold_timer, jiffies + BR_HOLD_TIME);
+ mod_timer(&p->hold_timer,
+ round_jiffies(jiffies + BR_HOLD_TIME));
}
}
/* called under bridge lock */
-static inline void br_record_config_information(struct net_bridge_port *p,
+static inline void br_record_config_information(struct net_bridge_port *p,
const struct br_config_bpdu *bpdu)
{
p->designated_root = bpdu->root;
p->designated_bridge = bpdu->bridge_id;
p->designated_port = bpdu->port_id;
- mod_timer(&p->message_age_timer, jiffies
+ mod_timer(&p->message_age_timer, jiffies
+ (p->br->max_age - bpdu->message_age));
}
/* called under bridge lock */
-static inline void br_record_config_timeout_values(struct net_bridge *br,
+static inline void br_record_config_timeout_values(struct net_bridge *br,
const struct br_config_bpdu *bpdu)
{
br->max_age = bpdu->max_age;
{
int isroot = br_is_root_bridge(br);
+ if (br->stp_enabled != BR_KERNEL_STP)
+ return;
+
pr_info("%s: topology change detected, %s\n", br->dev->name,
isroot ? "propagating" : "sending tcn bpdu");
/* called under bridge lock */
static void br_make_forwarding(struct net_bridge_port *p)
{
- if (p->state == BR_STATE_BLOCKING) {
- if (p->br->stp_enabled) {
- p->state = BR_STATE_LISTENING;
- } else {
- p->state = BR_STATE_LEARNING;
- }
- br_log_state(p);
- mod_timer(&p->forward_delay_timer, jiffies + p->br->forward_delay); }
+ struct net_bridge *br = p->br;
+
+ if (p->state != BR_STATE_BLOCKING)
+ return;
+
+ if (br->forward_delay == 0) {
+ p->state = BR_STATE_FORWARDING;
+ br_topology_change_detection(br);
+ del_timer(&p->forward_delay_timer);
+ }
+ else if (p->br->stp_enabled == BR_KERNEL_STP)
+ p->state = BR_STATE_LISTENING;
+ else
+ p->state = BR_STATE_LEARNING;
+
+ br_log_state(p);
+
+ if (br->forward_delay != 0)
+ mod_timer(&p->forward_delay_timer, jiffies + br->forward_delay);
}
/* called under bridge lock */
{
struct net_bridge_port *p;
+ /* Don't change port states if userspace is handling STP */
+ if (br->stp_enabled == BR_USER_STP)
+ return;
+
list_for_each_entry(p, &br->port_list, list) {
if (p->state != BR_STATE_DISABLED) {
if (p->port_no == br->root_port) {
{
struct net_bridge *br;
int was_root;
-
+
br = p->br;
was_root = br_is_root_bridge(br);
del_timer(&br->topology_change_timer);
br_transmit_tcn(br);
- mod_timer(&br->tcn_timer,
+ mod_timer(&br->tcn_timer,
jiffies + br->bridge_hello_time);
}
}
if (bpdu->topology_change_ack)
br_topology_change_acknowledged(br);
}
- } else if (br_is_designated_port(p)) {
- br_reply(p);
+ } else if (br_is_designated_port(p)) {
+ br_reply(p);
}
}