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
flush(STATE_MACH_T * this,char * reason)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
setTcPropBridge(STATE_MACH_T * this,char * reason)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
newTcWhile(STATE_MACH_T * this)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
STP_topoch_enter_state(STATE_MACH_T * this)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
STP_topoch_check_conditions(STATE_MACH_T * this)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