/* called under bridge lock */ static void br_check_timers(struct net_bridge *br) { struct net_bridge_port *p; if (br_timer_has_expired(&br->gc_timer, br->gc_interval)) { br_timer_set(&br->gc_timer, jiffies); br_fdb_cleanup(br); } if (br_timer_has_expired(&br->hello_timer, br->hello_time)) { br_timer_clear(&br->hello_timer); br_hello_timer_expired(br); } if (br_timer_has_expired(&br->tcn_timer, br->bridge_hello_time)) { br_timer_clear(&br->tcn_timer); br_tcn_timer_expired(br); } if (br_timer_has_expired(&br->topology_change_timer, br->bridge_forward_delay + br->bridge_max_age)) { br_timer_clear(&br->topology_change_timer); br_topology_change_timer_expired(br); } p = br->port_list; while (p != NULL) { if (p->state != BR_STATE_DISABLED) br_check_port_timers(p); p = p->next; } }
/* called under bridge lock */ void br_init_port(struct net_bridge_port *p) { p->port_id = br_make_port_id(p); br_become_designated_port(p); p->state = BR_STATE_BLOCKING; #if defined( CONFIG_RTL865X)&&defined(CONFIG_RE865X) { int retval=0, vlanPort; char name[IFNAMSIZ]; strcpy(name, p->dev->name); vlanPort=name[strlen(name)-1]-'0'; retval=rtl8651_setSpanningTreeInstancePortState(0, vlanPort,1); if(0==retval) printk("RTL865x Port %d state=BLOCKING\n", vlanPort); else printk("RTL865x port %d set state error=%d", vlanPort, retval); } #endif p->topology_change_ack = 0; p->config_pending = 0; br_timer_clear(&p->message_age_timer); br_timer_clear(&p->forward_delay_timer); br_timer_clear(&p->hold_timer); }
/* called under bridge lock */ void br_init_port(struct net_bridge_port *p) { p->port_id = br_make_port_id(p); br_become_designated_port(p); p->state = BR_STATE_BLOCKING; p->topology_change_ack = 0; p->config_pending = 0; br_timer_clear(&p->message_age_timer); br_timer_clear(&p->forward_delay_timer); br_timer_clear(&p->hold_timer); }
/* called under bridge lock */ static void br_make_blocking(struct net_bridge_port *p) { if (p->state != BR_STATE_DISABLED && p->state != BR_STATE_BLOCKING) { if (p->state == BR_STATE_FORWARDING || p->state == BR_STATE_LEARNING) br_topology_change_detection(p->br); printk(KERN_INFO "%s: port %i(%s) entering %s state\n", p->br->dev.name, p->port_no, p->dev->name, "blocking"); p->state = BR_STATE_BLOCKING; #if defined( CONFIG_RTL865X)&&defined(CONFIG_RE865X) { int retval=0, vlanPort; char name[IFNAMSIZ]; strcpy(name, p->dev->name); vlanPort=name[strlen(name)-1]-'0'; retval=rtl8651_setSpanningTreeInstancePortState(0, vlanPort,1); if(0==retval) printk("RTL865x Port %d state=BLOCKING\n", vlanPort); else printk("RTL865x port %d set state error=%d", vlanPort, retval); } #endif br_timer_clear(&p->forward_delay_timer); } }
/* called under bridge lock */ static void br_check_port_timers(struct net_bridge_port *p) { if (br_timer_has_expired(&p->message_age_timer, p->br->max_age)) { br_timer_clear(&p->message_age_timer); br_message_age_timer_expired(p); } if (br_timer_has_expired(&p->forward_delay_timer, p->br->forward_delay)) { br_timer_clear(&p->forward_delay_timer); br_forward_delay_timer_expired(p); } if (br_timer_has_expired(&p->hold_timer, BR_HOLD_TIME)) { br_timer_clear(&p->hold_timer); br_hold_timer_expired(p); } }
/* called under bridge lock */ void br_become_root_bridge(struct net_bridge *br) { br->max_age = br->bridge_max_age; br->hello_time = br->bridge_hello_time; br->forward_delay = br->bridge_forward_delay; br_topology_change_detection(br); br_timer_clear(&br->tcn_timer); br_timer_set(&br->hello_timer, jiffies - br->hello_time); }
static struct net_bridge *new_nb(char *name) { struct net_bridge *br; struct net_device *dev; if ((br = kmalloc(sizeof(*br), GFP_KERNEL)) == NULL) return NULL; memset(br, 0, sizeof(*br)); dev = &br->dev; strncpy(dev->name, name, IFNAMSIZ); dev->priv = br; ether_setup(dev); br_dev_setup(dev); br->lock = RW_LOCK_UNLOCKED; br->hash_lock = RW_LOCK_UNLOCKED; br->bridge_id.prio[0] = 0x80; br->bridge_id.prio[1] = 0x00; memset(br->bridge_id.addr, 0, ETH_ALEN); br->stp_enabled = 1; br->designated_root = br->bridge_id; br->root_path_cost = 0; br->root_port = 0; br->bridge_max_age = br->max_age = 20 * HZ; br->bridge_hello_time = br->hello_time = 2 * HZ; br->bridge_forward_delay = br->forward_delay = 15 * HZ; br->topology_change = 0; br->topology_change_detected = 0; br_timer_clear(&br->hello_timer); br_timer_clear(&br->tcn_timer); br_timer_clear(&br->topology_change_timer); br->ageing_time = 300 * HZ; br->gc_interval = 4 * HZ; return br; }
/* called under bridge lock */ void br_stp_disable_bridge(struct net_bridge *br) { struct net_bridge_port *p; br->topology_change = 0; br->topology_change_detected = 0; br_timer_clear(&br->hello_timer); br_timer_clear(&br->topology_change_timer); br_timer_clear(&br->tcn_timer); br_timer_clear(&br->gc_timer); br_fdb_cleanup(br); p = br->port_list; while (p != NULL) { if (p->state != BR_STATE_DISABLED) br_stp_disable_port(p); p = p->next; } del_timer(&br->tick); }
/* lock-safe */ void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu) { struct net_bridge *br; int was_root; if (p->state == BR_STATE_DISABLED) return; br = p->br; read_lock(&br->lock); was_root = br_is_root_bridge(br); if (br_supersedes_port_info(p, bpdu)) { br_record_config_information(p, bpdu); br_configuration_update(br); br_port_state_selection(br); if (!br_is_root_bridge(br) && was_root) { br_timer_clear(&br->hello_timer); if (br->topology_change_detected) { br_timer_clear(&br->topology_change_timer); br_transmit_tcn(br); br_timer_set(&br->tcn_timer, jiffies); } } if (p->port_no == br->root_port) { br_record_config_timeout_values(br, bpdu); br_config_bpdu_generation(br); if (bpdu->topology_change_ack) br_topology_change_acknowledged(br); } } else if (br_is_designated_port(p)) { br_reply(p); } read_unlock(&br->lock); }
/* called under bridge lock */ void br_stp_disable_port(struct net_bridge_port *p) { struct net_bridge *br; int wasroot; br = p->br; printk(KERN_INFO "%s: port %i(%s) entering %s state\n", br->dev.name, p->port_no, p->dev->name, "disabled"); wasroot = br_is_root_bridge(br); br_become_designated_port(p); p->state = BR_STATE_DISABLED; p->topology_change_ack = 0; p->config_pending = 0; br_timer_clear(&p->message_age_timer); br_timer_clear(&p->forward_delay_timer); br_timer_clear(&p->hold_timer); br_configuration_update(br); br_port_state_selection(br); if (br_is_root_bridge(br) && !wasroot) br_become_root_bridge(br); }
/* called under bridge lock */ static void br_make_blocking(struct net_bridge_port *p) { if (p->state != BR_STATE_DISABLED && p->state != BR_STATE_BLOCKING) { if (p->state == BR_STATE_FORWARDING || p->state == BR_STATE_LEARNING) br_topology_change_detection(p->br); // printk(KERN_INFO "%s: port %i(%s) entering %s state\n", // p->br->dev.name, p->port_no, p->dev->name, "blocking"); p->state = BR_STATE_BLOCKING; br_timer_clear(&p->forward_delay_timer); } }
/* called under bridge lock */ void br_port_state_selection(struct net_bridge *br) { struct net_bridge_port *p; p = br->port_list; while (p != NULL) { if (p->state != BR_STATE_DISABLED) { if (p->port_no == br->root_port) { p->config_pending = 0; p->topology_change_ack = 0; br_make_forwarding(p); } else if (br_is_designated_port(p)) { br_timer_clear(&p->message_age_timer); br_make_forwarding(p); } else { p->config_pending = 0; p->topology_change_ack = 0; br_make_blocking(p); } } p = p->next; } }
/* called under bridge lock */ static void br_topology_change_acknowledged(struct net_bridge *br) { br->topology_change_detected = 0; br_timer_clear(&br->tcn_timer); }