1 /* 2 * Spanning tree protocol; interface code 3 * Linux ethernet bridge 4 * 5 * Authors: 6 * Lennert Buytenhek <buytenh@gnu.org> 7 * 8 * $Id: br_stp_if.c,v 1.4 2001/04/14 21:14:39 davem Exp $ 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 13 * 2 of the License, or (at your option) any later version. 14 */ 15 16 #include <linux/kernel.h> 17 #include <linux/smp_lock.h> 18 #include <linux/etherdevice.h> 19 20 #include "br_private.h" 21 #include "br_private_stp.h" 22 23 24 /* Port id is composed of priority and port number. 25 * NB: least significant bits of priority are dropped to 26 * make room for more ports. 27 */ 28 static inline port_id br_make_port_id(__u8 priority, __u16 port_no) 29 { 30 return ((u16)priority << BR_PORT_BITS) 31 | (port_no & ((1<<BR_PORT_BITS)-1)); 32 } 33 34 /* called under bridge lock */ 35 void br_init_port(struct net_bridge_port *p) 36 { 37 p->port_id = br_make_port_id(p->priority, p->port_no); 38 br_become_designated_port(p); 39 p->state = BR_STATE_BLOCKING; 40 p->topology_change_ack = 0; 41 p->config_pending = 0; 42 } 43 44 /* called under bridge lock */ 45 void br_stp_enable_bridge(struct net_bridge *br) 46 { 47 struct net_bridge_port *p; 48 49 spin_lock_bh(&br->lock); 50 mod_timer(&br->hello_timer, jiffies + br->hello_time); 51 mod_timer(&br->gc_timer, jiffies + HZ/10); 52 53 br_config_bpdu_generation(br); 54 55 list_for_each_entry(p, &br->port_list, list) { 56 if ((p->dev->flags & IFF_UP) && netif_carrier_ok(p->dev)) 57 br_stp_enable_port(p); 58 59 } 60 spin_unlock_bh(&br->lock); 61 } 62 63 /* NO locks held */ 64 void br_stp_disable_bridge(struct net_bridge *br) 65 { 66 struct net_bridge_port *p; 67 68 spin_lock_bh(&br->lock); 69 list_for_each_entry(p, &br->port_list, list) { 70 if (p->state != BR_STATE_DISABLED) 71 br_stp_disable_port(p); 72 73 } 74 75 br->topology_change = 0; 76 br->topology_change_detected = 0; 77 spin_unlock_bh(&br->lock); 78 79 del_timer_sync(&br->hello_timer); 80 del_timer_sync(&br->topology_change_timer); 81 del_timer_sync(&br->tcn_timer); 82 del_timer_sync(&br->gc_timer); 83 } 84 85 /* called under bridge lock */ 86 void br_stp_enable_port(struct net_bridge_port *p) 87 { 88 br_init_port(p); 89 br_port_state_selection(p->br); 90 } 91 92 /* called under bridge lock */ 93 void br_stp_disable_port(struct net_bridge_port *p) 94 { 95 struct net_bridge *br; 96 int wasroot; 97 98 br = p->br; 99 printk(KERN_INFO "%s: port %i(%s) entering %s state\n", 100 br->dev->name, p->port_no, p->dev->name, "disabled"); 101 102 wasroot = br_is_root_bridge(br); 103 br_become_designated_port(p); 104 p->state = BR_STATE_DISABLED; 105 p->topology_change_ack = 0; 106 p->config_pending = 0; 107 108 del_timer(&p->message_age_timer); 109 del_timer(&p->forward_delay_timer); 110 del_timer(&p->hold_timer); 111 112 br_configuration_update(br); 113 114 br_port_state_selection(br); 115 116 if (br_is_root_bridge(br) && !wasroot) 117 br_become_root_bridge(br); 118 } 119 120 /* called under bridge lock */ 121 void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr) 122 { 123 unsigned char oldaddr[6]; 124 struct net_bridge_port *p; 125 int wasroot; 126 127 wasroot = br_is_root_bridge(br); 128 129 memcpy(oldaddr, br->bridge_id.addr, ETH_ALEN); 130 memcpy(br->bridge_id.addr, addr, ETH_ALEN); 131 memcpy(br->dev->dev_addr, addr, ETH_ALEN); 132 133 list_for_each_entry(p, &br->port_list, list) { 134 if (!compare_ether_addr(p->designated_bridge.addr, oldaddr)) 135 memcpy(p->designated_bridge.addr, addr, ETH_ALEN); 136 137 if (!compare_ether_addr(p->designated_root.addr, oldaddr)) 138 memcpy(p->designated_root.addr, addr, ETH_ALEN); 139 140 } 141 142 br_configuration_update(br); 143 br_port_state_selection(br); 144 if (br_is_root_bridge(br) && !wasroot) 145 br_become_root_bridge(br); 146 } 147 148 static const unsigned char br_mac_zero[6]; 149 150 /* called under bridge lock */ 151 void br_stp_recalculate_bridge_id(struct net_bridge *br) 152 { 153 const unsigned char *addr = br_mac_zero; 154 struct net_bridge_port *p; 155 156 list_for_each_entry(p, &br->port_list, list) { 157 if (addr == br_mac_zero || 158 memcmp(p->dev->dev_addr, addr, ETH_ALEN) < 0) 159 addr = p->dev->dev_addr; 160 161 } 162 163 if (compare_ether_addr(br->bridge_id.addr, addr)) 164 br_stp_change_bridge_id(br, addr); 165 } 166 167 /* called under bridge lock */ 168 void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio) 169 { 170 struct net_bridge_port *p; 171 int wasroot; 172 173 wasroot = br_is_root_bridge(br); 174 175 list_for_each_entry(p, &br->port_list, list) { 176 if (p->state != BR_STATE_DISABLED && 177 br_is_designated_port(p)) { 178 p->designated_bridge.prio[0] = (newprio >> 8) & 0xFF; 179 p->designated_bridge.prio[1] = newprio & 0xFF; 180 } 181 182 } 183 184 br->bridge_id.prio[0] = (newprio >> 8) & 0xFF; 185 br->bridge_id.prio[1] = newprio & 0xFF; 186 br_configuration_update(br); 187 br_port_state_selection(br); 188 if (br_is_root_bridge(br) && !wasroot) 189 br_become_root_bridge(br); 190 } 191 192 /* called under bridge lock */ 193 void br_stp_set_port_priority(struct net_bridge_port *p, u8 newprio) 194 { 195 port_id new_port_id = br_make_port_id(newprio, p->port_no); 196 197 if (br_is_designated_port(p)) 198 p->designated_port = new_port_id; 199 200 p->port_id = new_port_id; 201 p->priority = newprio; 202 if (!memcmp(&p->br->bridge_id, &p->designated_bridge, 8) && 203 p->port_id < p->designated_port) { 204 br_become_designated_port(p); 205 br_port_state_selection(p->br); 206 } 207 } 208 209 /* called under bridge lock */ 210 void br_stp_set_path_cost(struct net_bridge_port *p, u32 path_cost) 211 { 212 p->path_cost = path_cost; 213 br_configuration_update(p->br); 214 br_port_state_selection(p->br); 215 } 216 217 ssize_t br_show_bridge_id(char *buf, const struct bridge_id *id) 218 { 219 return sprintf(buf, "%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x\n", 220 id->prio[0], id->prio[1], 221 id->addr[0], id->addr[1], id->addr[2], 222 id->addr[3], id->addr[4], id->addr[5]); 223 } 224