/* called under bridge lock */ void br_topology_change_detection(struct net_bridge *br) { // printk(KERN_INFO "%s: topology change detected", br->dev.name); if (br_is_root_bridge(br)) { // printk(", propagating"); br->topology_change = 1; br_timer_set(&br->topology_change_timer, jiffies); } else if (!br->topology_change_detected) { // printk(", sending tcn bpdu"); br_transmit_tcn(br); br_timer_set(&br->tcn_timer, jiffies); } // printk("\n"); br->topology_change_detected = 1; }
/* 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 */ static void br_tcn_timer_expired(struct net_bridge *br) { printk(KERN_INFO "%s: retransmitting tcn bpdu\n", br->dev.name); br_transmit_tcn(br); br_timer_set(&br->tcn_timer, jiffies); }