1 /************************************************************************ 2 * RSTP library - Rapid Spanning Tree (802.1t, 802.1w) 3 * Copyright (C) 2001-2003 Optical Access 4 * Author: Alex Rozin 5 * 6 * This file is part of RSTP library. 7 * 8 * RSTP library is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU Lesser General Public License as published by the 10 * Free Software Foundation; version 2.1 11 * 12 * RSTP library is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public License 18 * along with RSTP library; see the file COPYING. If not, write to the Free 19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 20 * 02111-1307, USA. 21 **********************************************************************/ 22 23 /* Port Transmit state machine : 17.27 */ 24 25 #include "base.h" 26 #include "stpm.h" 27 #include "stp_to.h" /* for STP_OUT_get_port_mac & STP_OUT_tx_bpdu */ 28 29 #define BPDU_LEN8023_OFF 12 30 31 #define STATES { \ 32 CHOOSE(TRANSMIT_INIT), \ 33 CHOOSE(TRANSMIT_PERIODIC), \ 34 CHOOSE(IDLE), \ 35 CHOOSE(TRANSMIT_CONFIG), \ 36 CHOOSE(TRANSMIT_TCN), \ 37 CHOOSE(TRANSMIT_RSTP) \ 38 } 39 40 #define GET_STATE_NAME STP_transmit_get_state_name 41 #include "choose.h" 42 43 #define MIN_FRAME_LENGTH 64 44 45 46 typedef struct tx_tcn_bpdu_t { 47 MAC_HEADER_T mac; 48 ETH_HEADER_T eth; 49 BPDU_HEADER_T hdr; 50 } TCN_BPDU_T; 51 52 typedef struct tx_stp_bpdu_t { 53 MAC_HEADER_T mac; 54 ETH_HEADER_T eth; 55 BPDU_HEADER_T hdr; 56 BPDU_BODY_T body; 57 } CONFIG_BPDU_T; 58 59 typedef struct tx_rstp_bpdu_t { 60 MAC_HEADER_T mac; 61 ETH_HEADER_T eth; 62 BPDU_HEADER_T hdr; 63 BPDU_BODY_T body; 64 unsigned char ver_1_length[2]; 65 } RSTP_BPDU_T; 66 67 68 static RSTP_BPDU_T bpdu_packet = { 69 {/* MAC_HEADER_T */ 70 {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00}, /* dst_mac */ 71 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* src_mac */ 72 }, 73 { /* ETH_HEADER_T */ 74 {0x00, 0x00}, /* len8023 */ 75 BPDU_L_SAP, BPDU_L_SAP, LLC_UI /* dsap, ssap, llc */ 76 }, 77 {/* BPDU_HEADER_T */ 78 {0x00, 0x00}, /* protocol */ 79 BPDU_VERSION_ID, 0x00 /* version, bpdu_type */ 80 }, 81 { 82 0x00, /* flags; */ 83 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /* root_id[8]; */ 84 {0x00,0x00,0x00,0x00}, /* root_path_cost[4]; */ 85 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /* bridge_id[8]; */ 86 {0x00,0x00}, /* port_id[2]; */ 87 {0x00,0x00}, /* message_age[2]; */ 88 {0x00,0x00}, /* max_age[2]; */ 89 {0x00,0x00}, /* hello_time[2]; */ 90 {0x00,0x00}, /* forward_delay[2]; */ 91 }, 92 {0x00,0x00}, /* ver_1_length[2]; */ 93 }; 94 95 static size_t 96 build_bpdu_header (int port_index, 97 unsigned char bpdu_type, 98 unsigned short pkt_len) 99 { 100 unsigned short len8023; 101 102 STP_OUT_get_port_mac (port_index, bpdu_packet.mac.src_mac); 103 104 bpdu_packet.hdr.bpdu_type = bpdu_type; 105 bpdu_packet.hdr.version = (BPDU_RSTP == bpdu_type) ? 106 BPDU_VERSION_RAPID_ID : 107 BPDU_VERSION_ID; 108 109 /* NOTE: I suppose, that sizeof(unsigned short)=2 ! */ 110 len8023 = htons ((unsigned short) (pkt_len + 3)); 111 (void) memcpy (&bpdu_packet.eth.len8023, &len8023, 2); 112 113 if (pkt_len < MIN_FRAME_LENGTH) pkt_len = MIN_FRAME_LENGTH; 114 return pkt_len; 115 } 116 117 static int 118 txTcn (STATE_MACH_T* this) 119 { /* 17.19.17 (page 68) & 9.3.2 (page 25) */ 120 register size_t pkt_len; 121 register int port_index, vlan_id; 122 123 #ifdef STP_DBG 124 if (this->owner.port->skip_tx > 0) { 125 if (1 == this->owner.port->skip_tx) 126 stp_trace ("port %s stop tx skipping", 127 this->owner.port->port_name); 128 this->owner.port->skip_tx--; 129 return STP_Nothing_To_Do; 130 } 131 #endif 132 133 if (this->owner.port->admin_non_stp) return 1; 134 port_index = this->owner.port->port_index; 135 vlan_id = this->owner.port->owner->vlan_id; 136 137 pkt_len = build_bpdu_header (port_index, 138 BPDU_TOPO_CHANGE_TYPE, 139 sizeof (BPDU_HEADER_T)); 140 141 #ifdef STP_DBG 142 if (this->debug) 143 stp_trace ("port %s txTcn", this->owner.port->port_name); 144 #endif 145 return STP_OUT_tx_bpdu (port_index, vlan_id, 146 (unsigned char *) &bpdu_packet, 147 pkt_len); 148 } 149 150 static void 151 build_config_bpdu (PORT_T* port, Bool set_topo_ack_flag) 152 { 153 bpdu_packet.body.flags = 0; 154 if (port->tcWhile) { 155 #ifdef STP_DBG 156 if (port->topoch->debug) 157 stp_trace ("tcWhile=%d =>tx TOPOLOGY_CHANGE_BIT to port %s", 158 (int) port->tcWhile, port->port_name); 159 #endif 160 bpdu_packet.body.flags |= TOPOLOGY_CHANGE_BIT; 161 } 162 163 if (set_topo_ack_flag && port->tcAck) { 164 bpdu_packet.body.flags |= TOPOLOGY_CHANGE_ACK_BIT; 165 } 166 167 STP_VECT_set_vector (&port->portPrio, &bpdu_packet.body); 168 STP_set_times (&port->portTimes, &bpdu_packet.body); 169 } 170 171 static int 172 txConfig (STATE_MACH_T* this) 173 {/* 17.19.15 (page 67) & 9.3.1 (page 23) */ 174 register size_t pkt_len; 175 register PORT_T* port = NULL; 176 register int port_index, vlan_id; 177 178 #ifdef STP_DBG 179 if (this->owner.port->skip_tx > 0) { 180 if (1 == this->owner.port->skip_tx) 181 stp_trace ("port %s stop tx skipping", 182 this->owner.port->port_name); 183 this->owner.port->skip_tx--; 184 return STP_Nothing_To_Do; 185 } 186 #endif 187 188 port = this->owner.port; 189 if (port->admin_non_stp) return 1; 190 port_index = port->port_index; 191 vlan_id = port->owner->vlan_id; 192 193 pkt_len = build_bpdu_header (port->port_index, 194 BPDU_CONFIG_TYPE, 195 sizeof (BPDU_HEADER_T) + sizeof (BPDU_BODY_T)); 196 build_config_bpdu (port, True); 197 198 #ifdef STP_DBG 199 if (this->debug) 200 stp_trace ("port %s txConfig flags=0X%lx", 201 port->port_name, 202 (unsigned long) bpdu_packet.body.flags); 203 #endif 204 return STP_OUT_tx_bpdu (port_index, vlan_id, 205 (unsigned char *) &bpdu_packet, 206 pkt_len); 207 } 208 209 static int 210 txRstp (STATE_MACH_T* this) 211 {/* 17.19.16 (page 68) & 9.3.3 (page 25) */ 212 register size_t pkt_len; 213 register PORT_T* port = NULL; 214 register int port_index, vlan_id; 215 unsigned char role; 216 217 #ifdef STP_DBG 218 if (this->owner.port->skip_tx > 0) { 219 if (1 == this->owner.port->skip_tx) 220 stp_trace ("port %s stop tx skipping", 221 this->owner.port->port_name); 222 else 223 stp_trace ("port %s skip tx %d", 224 this->owner.port->port_name, this->owner.port->skip_tx); 225 226 this->owner.port->skip_tx--; 227 return STP_Nothing_To_Do; 228 } 229 #endif 230 231 port = this->owner.port; 232 if (port->admin_non_stp) return 1; 233 port_index = port->port_index; 234 vlan_id = port->owner->vlan_id; 235 236 pkt_len = build_bpdu_header (port->port_index, 237 BPDU_RSTP, 238 sizeof (BPDU_HEADER_T) + sizeof (BPDU_BODY_T) + 2); 239 build_config_bpdu (port, False); 240 241 switch (port->selectedRole) { 242 default: 243 case DisabledPort: 244 role = RSTP_PORT_ROLE_UNKN; 245 break; 246 case AlternatePort: 247 role = RSTP_PORT_ROLE_ALTBACK; 248 break; 249 case BackupPort: 250 role = RSTP_PORT_ROLE_ALTBACK; 251 break; 252 case RootPort: 253 role = RSTP_PORT_ROLE_ROOT; 254 break; 255 case DesignatedPort: 256 role = RSTP_PORT_ROLE_DESGN; 257 break; 258 } 259 260 bpdu_packet.body.flags |= (role << PORT_ROLE_OFFS); 261 262 if (port->synced) { 263 #if 0 /* def STP_DBG */ 264 if (port->roletrns->debug) 265 stp_trace ("tx AGREEMENT_BIT to port %s", port->port_name); 266 #endif 267 bpdu_packet.body.flags |= AGREEMENT_BIT; 268 } 269 270 if (port->proposing) { 271 #if 0 /* def STP_DBG */ 272 if (port->roletrns->debug) 273 stp_trace ("tx PROPOSAL_BIT to port %s", port->port_name); 274 #endif 275 bpdu_packet.body.flags |= PROPOSAL_BIT; 276 } 277 278 #ifdef STP_DBG 279 if (this->debug) 280 stp_trace ("port %s txRstp flags=0X%lx", 281 port->port_name, 282 (unsigned long) bpdu_packet.body.flags); 283 #endif 284 285 return STP_OUT_tx_bpdu (port_index, vlan_id, 286 (unsigned char *) &bpdu_packet, 287 pkt_len); 288 } 289 290 void 291 STP_transmit_enter_state (STATE_MACH_T* this) 292 { 293 register PORT_T* port = this->owner.port; 294 295 switch (this->State) { 296 case BEGIN: 297 case TRANSMIT_INIT: 298 port->newInfo = False; 299 port->helloWhen = 0; 300 port->txCount = 0; 301 break; 302 case TRANSMIT_PERIODIC: 303 port->newInfo = port->newInfo || 304 ((port->role == DesignatedPort) || 305 ((port->role == RootPort) && port->tcWhile)); 306 port->helloWhen = port->owner->rootTimes.HelloTime; 307 break; 308 case IDLE: 309 break; 310 case TRANSMIT_CONFIG: 311 port->newInfo = False; 312 (void) txConfig (this); 313 port->txCount++; 314 port->tcAck = False; 315 break; 316 case TRANSMIT_TCN: 317 port->newInfo = False; 318 (void) txTcn (this); 319 port->txCount++; 320 break; 321 case TRANSMIT_RSTP: 322 port->newInfo = False; 323 (void) txRstp (this); 324 port->txCount++; 325 port->tcAck = False; 326 break; 327 }; 328 } 329 330 Bool 331 STP_transmit_check_conditions (STATE_MACH_T* this) 332 { 333 register PORT_T* port = this->owner.port; 334 335 switch (this->State) { 336 case BEGIN: 337 return STP_hop_2_state (this, TRANSMIT_INIT); 338 case TRANSMIT_INIT: 339 return STP_hop_2_state (this, IDLE); 340 case TRANSMIT_PERIODIC: 341 return STP_hop_2_state (this, IDLE); 342 case IDLE: 343 if (!port->helloWhen) return STP_hop_2_state (this, TRANSMIT_PERIODIC); 344 if (!port->sendRSTP && port->newInfo && 345 (port->txCount < TxHoldCount) && 346 (port->role == DesignatedPort) && 347 port->helloWhen) 348 return STP_hop_2_state (this, TRANSMIT_CONFIG); 349 if (!port->sendRSTP && port->newInfo && 350 (port->txCount < TxHoldCount) && 351 (port->role == RootPort) && 352 port->helloWhen) 353 return STP_hop_2_state (this, TRANSMIT_TCN); 354 if (port->sendRSTP && port->newInfo && 355 (port->txCount < TxHoldCount) && 356 ((port->role == RootPort) || 357 (port->role == DesignatedPort))) 358 return STP_hop_2_state (this, TRANSMIT_RSTP); 359 break; 360 case TRANSMIT_CONFIG: 361 return STP_hop_2_state (this, IDLE); 362 case TRANSMIT_TCN: 363 return STP_hop_2_state (this, IDLE); 364 case TRANSMIT_RSTP: 365 return STP_hop_2_state (this, IDLE); 366 }; 367 return False; 368 } 369