1*4eaa4710SRishi Srivatsavai /************************************************************************ 2*4eaa4710SRishi Srivatsavai * RSTP library - Rapid Spanning Tree (802.1t, 802.1w) 3*4eaa4710SRishi Srivatsavai * Copyright (C) 2001-2003 Optical Access 4*4eaa4710SRishi Srivatsavai * Author: Alex Rozin 5*4eaa4710SRishi Srivatsavai * 6*4eaa4710SRishi Srivatsavai * This file is part of RSTP library. 7*4eaa4710SRishi Srivatsavai * 8*4eaa4710SRishi Srivatsavai * RSTP library is free software; you can redistribute it and/or modify it 9*4eaa4710SRishi Srivatsavai * under the terms of the GNU Lesser General Public License as published by the 10*4eaa4710SRishi Srivatsavai * Free Software Foundation; version 2.1 11*4eaa4710SRishi Srivatsavai * 12*4eaa4710SRishi Srivatsavai * RSTP library is distributed in the hope that it will be useful, but 13*4eaa4710SRishi Srivatsavai * WITHOUT ANY WARRANTY; without even the implied warranty of 14*4eaa4710SRishi Srivatsavai * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 15*4eaa4710SRishi Srivatsavai * General Public License for more details. 16*4eaa4710SRishi Srivatsavai * 17*4eaa4710SRishi Srivatsavai * You should have received a copy of the GNU Lesser General Public License 18*4eaa4710SRishi Srivatsavai * along with RSTP library; see the file COPYING. If not, write to the Free 19*4eaa4710SRishi Srivatsavai * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 20*4eaa4710SRishi Srivatsavai * 02111-1307, USA. 21*4eaa4710SRishi Srivatsavai **********************************************************************/ 22*4eaa4710SRishi Srivatsavai 23*4eaa4710SRishi Srivatsavai /* Topolgy Change state machine : 17.25 */ 24*4eaa4710SRishi Srivatsavai 25*4eaa4710SRishi Srivatsavai #include "base.h" 26*4eaa4710SRishi Srivatsavai #include "stpm.h" 27*4eaa4710SRishi Srivatsavai #include "stp_to.h" /* for STP_OUT_flush_lt */ 28*4eaa4710SRishi Srivatsavai 29*4eaa4710SRishi Srivatsavai #define STATES { \ 30*4eaa4710SRishi Srivatsavai CHOOSE(INIT), \ 31*4eaa4710SRishi Srivatsavai CHOOSE(INACTIVE), \ 32*4eaa4710SRishi Srivatsavai CHOOSE(TCACTIVE), \ 33*4eaa4710SRishi Srivatsavai CHOOSE(DETECTED), \ 34*4eaa4710SRishi Srivatsavai CHOOSE(NOTIFIED_TC), \ 35*4eaa4710SRishi Srivatsavai CHOOSE(PROPAGATING), \ 36*4eaa4710SRishi Srivatsavai CHOOSE(ACKNOWLEDGED), \ 37*4eaa4710SRishi Srivatsavai CHOOSE(NOTIFIED_TCN) \ 38*4eaa4710SRishi Srivatsavai } 39*4eaa4710SRishi Srivatsavai 40*4eaa4710SRishi Srivatsavai #define GET_STATE_NAME STP_topoch_get_state_name 41*4eaa4710SRishi Srivatsavai #include "choose.h" 42*4eaa4710SRishi Srivatsavai 43*4eaa4710SRishi Srivatsavai #ifndef STRONGLY_SPEC_802_1W 44*4eaa4710SRishi Srivatsavai /* 45*4eaa4710SRishi Srivatsavai * In many kinds of hardware the function 46*4eaa4710SRishi Srivatsavai * STP_OUT_flush_lt is a) is very hard and b) cannot 47*4eaa4710SRishi Srivatsavai * delete learning emtries per port. The alternate 48*4eaa4710SRishi Srivatsavai * method may be used: we don't care operEdge flag here, 49*4eaa4710SRishi Srivatsavai * but clean learning table once for TopologyChange 50*4eaa4710SRishi Srivatsavai * for all ports, except the received port. I am ready to discuss :( 51*4eaa4710SRishi Srivatsavai * See below word STRONGLY_SPEC_802_1W 52*4eaa4710SRishi Srivatsavai */ 53*4eaa4710SRishi Srivatsavai #else 54*4eaa4710SRishi Srivatsavai static Bool 55*4eaa4710SRishi Srivatsavai flush (STATE_MACH_T *this, char* reason) /* 17.19.9 */ 56*4eaa4710SRishi Srivatsavai { 57*4eaa4710SRishi Srivatsavai register PORT_T* port = this->owner.port; 58*4eaa4710SRishi Srivatsavai Bool bret; 59*4eaa4710SRishi Srivatsavai 60*4eaa4710SRishi Srivatsavai if (port->operEdge) return True; 61*4eaa4710SRishi Srivatsavai if (this->debug) { 62*4eaa4710SRishi Srivatsavai stp_trace("%s (%s, %s, %s, '%s')", 63*4eaa4710SRishi Srivatsavai "flush", port->port_name, port->owner->name, 64*4eaa4710SRishi Srivatsavai LT_FLASH_ONLY_THE_PORT == type ? "this port" : "other ports", 65*4eaa4710SRishi Srivatsavai reason); 66*4eaa4710SRishi Srivatsavai } 67*4eaa4710SRishi Srivatsavai 68*4eaa4710SRishi Srivatsavai bret = STP_OUT_flush_lt (port->port_index, port->owner->vlan_id, 69*4eaa4710SRishi Srivatsavai LT_FLASH_ONLY_THE_PORT, reason); 70*4eaa4710SRishi Srivatsavai } 71*4eaa4710SRishi Srivatsavai #endif 72*4eaa4710SRishi Srivatsavai 73*4eaa4710SRishi Srivatsavai static void 74*4eaa4710SRishi Srivatsavai setTcPropBridge (STATE_MACH_T* this, char* reason) /* 17.19.14 */ 75*4eaa4710SRishi Srivatsavai { 76*4eaa4710SRishi Srivatsavai register PORT_T* port = this->owner.port; 77*4eaa4710SRishi Srivatsavai register PORT_T* tmp; 78*4eaa4710SRishi Srivatsavai 79*4eaa4710SRishi Srivatsavai for (tmp = port->owner->ports; tmp; tmp = tmp->next) { 80*4eaa4710SRishi Srivatsavai if (tmp->port_index != port->port_index) 81*4eaa4710SRishi Srivatsavai tmp->tcProp = True; 82*4eaa4710SRishi Srivatsavai } 83*4eaa4710SRishi Srivatsavai 84*4eaa4710SRishi Srivatsavai #ifndef STRONGLY_SPEC_802_1W 85*4eaa4710SRishi Srivatsavai #ifdef STP_DBG 86*4eaa4710SRishi Srivatsavai if (this->debug) { 87*4eaa4710SRishi Srivatsavai stp_trace("%s (%s, %s, %s, '%s')", 88*4eaa4710SRishi Srivatsavai "clearFDB", port->port_name, port->owner->name, 89*4eaa4710SRishi Srivatsavai "other ports", reason); 90*4eaa4710SRishi Srivatsavai } 91*4eaa4710SRishi Srivatsavai #endif 92*4eaa4710SRishi Srivatsavai 93*4eaa4710SRishi Srivatsavai STP_OUT_flush_lt (port->port_index, port->owner->vlan_id, 94*4eaa4710SRishi Srivatsavai LT_FLASH_ALL_PORTS_EXCLUDE_THIS, reason); 95*4eaa4710SRishi Srivatsavai #endif 96*4eaa4710SRishi Srivatsavai } 97*4eaa4710SRishi Srivatsavai 98*4eaa4710SRishi Srivatsavai static unsigned int 99*4eaa4710SRishi Srivatsavai newTcWhile (STATE_MACH_T* this) /* 17.19.7 */ 100*4eaa4710SRishi Srivatsavai { 101*4eaa4710SRishi Srivatsavai register PORT_T* port = this->owner.port; 102*4eaa4710SRishi Srivatsavai 103*4eaa4710SRishi Srivatsavai if (port->sendRSTP && port->operPointToPointMac) { 104*4eaa4710SRishi Srivatsavai return 2 * port->owner->rootTimes.HelloTime; 105*4eaa4710SRishi Srivatsavai } 106*4eaa4710SRishi Srivatsavai return port->owner->rootTimes.MaxAge; 107*4eaa4710SRishi Srivatsavai } 108*4eaa4710SRishi Srivatsavai 109*4eaa4710SRishi Srivatsavai void 110*4eaa4710SRishi Srivatsavai STP_topoch_enter_state (STATE_MACH_T* this) 111*4eaa4710SRishi Srivatsavai { 112*4eaa4710SRishi Srivatsavai register PORT_T* port = this->owner.port; 113*4eaa4710SRishi Srivatsavai 114*4eaa4710SRishi Srivatsavai switch (this->State) { 115*4eaa4710SRishi Srivatsavai case BEGIN: 116*4eaa4710SRishi Srivatsavai case INIT: 117*4eaa4710SRishi Srivatsavai #ifdef STRONGLY_SPEC_802_1W 118*4eaa4710SRishi Srivatsavai flush (this, "topoch INIT"); 119*4eaa4710SRishi Srivatsavai #endif 120*4eaa4710SRishi Srivatsavai port->tcWhile = 0; 121*4eaa4710SRishi Srivatsavai port->tc = 122*4eaa4710SRishi Srivatsavai port->tcProp = 123*4eaa4710SRishi Srivatsavai port->tcAck = False; 124*4eaa4710SRishi Srivatsavai break; 125*4eaa4710SRishi Srivatsavai case INACTIVE: 126*4eaa4710SRishi Srivatsavai port->rcvdTc = 127*4eaa4710SRishi Srivatsavai port->rcvdTcn = 128*4eaa4710SRishi Srivatsavai port->rcvdTcAck = port->tc = port->tcProp = False; 129*4eaa4710SRishi Srivatsavai break; 130*4eaa4710SRishi Srivatsavai case TCACTIVE: 131*4eaa4710SRishi Srivatsavai break; 132*4eaa4710SRishi Srivatsavai case DETECTED: 133*4eaa4710SRishi Srivatsavai port->tcWhile = newTcWhile (this); 134*4eaa4710SRishi Srivatsavai #ifdef STP_DBG 135*4eaa4710SRishi Srivatsavai if (this->debug) 136*4eaa4710SRishi Srivatsavai stp_trace("DETECTED: tcWhile=%d on port %s", 137*4eaa4710SRishi Srivatsavai port->tcWhile, port->port_name); 138*4eaa4710SRishi Srivatsavai #endif 139*4eaa4710SRishi Srivatsavai setTcPropBridge (this, "DETECTED"); 140*4eaa4710SRishi Srivatsavai port->tc = False; 141*4eaa4710SRishi Srivatsavai break; 142*4eaa4710SRishi Srivatsavai case NOTIFIED_TC: 143*4eaa4710SRishi Srivatsavai port->rcvdTcn = port->rcvdTc = False; 144*4eaa4710SRishi Srivatsavai if (port->role == DesignatedPort) { 145*4eaa4710SRishi Srivatsavai port->tcAck = True; 146*4eaa4710SRishi Srivatsavai } 147*4eaa4710SRishi Srivatsavai setTcPropBridge (this, "NOTIFIED_TC"); 148*4eaa4710SRishi Srivatsavai break; 149*4eaa4710SRishi Srivatsavai case PROPAGATING: 150*4eaa4710SRishi Srivatsavai port->tcWhile = newTcWhile (this); 151*4eaa4710SRishi Srivatsavai #ifdef STP_DBG 152*4eaa4710SRishi Srivatsavai if (this->debug) 153*4eaa4710SRishi Srivatsavai stp_trace("PROPAGATING: tcWhile=%d on port %s", 154*4eaa4710SRishi Srivatsavai port->tcWhile, port->port_name); 155*4eaa4710SRishi Srivatsavai #endif 156*4eaa4710SRishi Srivatsavai #ifdef STRONGLY_SPEC_802_1W 157*4eaa4710SRishi Srivatsavai flush (this, "topoch PROPAGATING"); 158*4eaa4710SRishi Srivatsavai #endif 159*4eaa4710SRishi Srivatsavai port->tcProp = False; 160*4eaa4710SRishi Srivatsavai break; 161*4eaa4710SRishi Srivatsavai case ACKNOWLEDGED: 162*4eaa4710SRishi Srivatsavai port->tcWhile = 0; 163*4eaa4710SRishi Srivatsavai #ifdef STP_DBG 164*4eaa4710SRishi Srivatsavai if (this->debug) 165*4eaa4710SRishi Srivatsavai stp_trace("ACKNOWLEDGED: tcWhile=%d on port %s", 166*4eaa4710SRishi Srivatsavai port->tcWhile, port->port_name); 167*4eaa4710SRishi Srivatsavai #endif 168*4eaa4710SRishi Srivatsavai port->rcvdTcAck = False; 169*4eaa4710SRishi Srivatsavai break; 170*4eaa4710SRishi Srivatsavai case NOTIFIED_TCN: 171*4eaa4710SRishi Srivatsavai port->tcWhile = newTcWhile (this); 172*4eaa4710SRishi Srivatsavai #ifdef STP_DBG 173*4eaa4710SRishi Srivatsavai if (this->debug) 174*4eaa4710SRishi Srivatsavai stp_trace("NOTIFIED_TCN: tcWhile=%d on port %s", 175*4eaa4710SRishi Srivatsavai port->tcWhile, port->port_name); 176*4eaa4710SRishi Srivatsavai #endif 177*4eaa4710SRishi Srivatsavai break; 178*4eaa4710SRishi Srivatsavai }; 179*4eaa4710SRishi Srivatsavai } 180*4eaa4710SRishi Srivatsavai 181*4eaa4710SRishi Srivatsavai Bool 182*4eaa4710SRishi Srivatsavai STP_topoch_check_conditions (STATE_MACH_T* this) 183*4eaa4710SRishi Srivatsavai { 184*4eaa4710SRishi Srivatsavai register PORT_T* port = this->owner.port; 185*4eaa4710SRishi Srivatsavai 186*4eaa4710SRishi Srivatsavai if (BEGIN == this->State) { 187*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, INIT); 188*4eaa4710SRishi Srivatsavai } 189*4eaa4710SRishi Srivatsavai 190*4eaa4710SRishi Srivatsavai switch (this->State) { 191*4eaa4710SRishi Srivatsavai case INIT: 192*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, INACTIVE); 193*4eaa4710SRishi Srivatsavai case INACTIVE: 194*4eaa4710SRishi Srivatsavai if (port->role == RootPort || port->role == DesignatedPort) 195*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, TCACTIVE); 196*4eaa4710SRishi Srivatsavai if (port->rcvdTc || port->rcvdTcn || port->rcvdTcAck || 197*4eaa4710SRishi Srivatsavai port->tc || port->tcProp) 198*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, INACTIVE); 199*4eaa4710SRishi Srivatsavai break; 200*4eaa4710SRishi Srivatsavai case TCACTIVE: 201*4eaa4710SRishi Srivatsavai if (port->role != RootPort && (port->role != DesignatedPort)) 202*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, INIT); 203*4eaa4710SRishi Srivatsavai if (port->tc) 204*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, DETECTED); 205*4eaa4710SRishi Srivatsavai if (port->rcvdTcn) 206*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, NOTIFIED_TCN); 207*4eaa4710SRishi Srivatsavai if (port->rcvdTc) 208*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, NOTIFIED_TC); 209*4eaa4710SRishi Srivatsavai if (port->tcProp && !port->operEdge) 210*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, PROPAGATING); 211*4eaa4710SRishi Srivatsavai if (port->rcvdTcAck) 212*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, ACKNOWLEDGED); 213*4eaa4710SRishi Srivatsavai break; 214*4eaa4710SRishi Srivatsavai case DETECTED: 215*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, TCACTIVE); 216*4eaa4710SRishi Srivatsavai case NOTIFIED_TC: 217*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, TCACTIVE); 218*4eaa4710SRishi Srivatsavai case PROPAGATING: 219*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, TCACTIVE); 220*4eaa4710SRishi Srivatsavai case ACKNOWLEDGED: 221*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, TCACTIVE); 222*4eaa4710SRishi Srivatsavai case NOTIFIED_TCN: 223*4eaa4710SRishi Srivatsavai return STP_hop_2_state (this, NOTIFIED_TC); 224*4eaa4710SRishi Srivatsavai }; 225*4eaa4710SRishi Srivatsavai return False; 226*4eaa4710SRishi Srivatsavai } 227*4eaa4710SRishi Srivatsavai 228