1 /************************************************************************
2 * RSTP library - Rapid Spanning Tree (802.1t, 802.1w)
3 * Copyright (C) 2001-2003 Optical Access
6 * This file is part of RSTP library.
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
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.
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
21 **********************************************************************/
23 /* Topolgy Change state machine : 17.25 */
27 #include "stp_to.h" /* for STP_OUT_flush_lt */
34 CHOOSE(NOTIFIED_TC), \
35 CHOOSE(PROPAGATING), \
36 CHOOSE(ACKNOWLEDGED), \
37 CHOOSE(NOTIFIED_TCN) \
40 #define GET_STATE_NAME STP_topoch_get_state_name
43 #ifndef STRONGLY_SPEC_802_1W
45 * In many kinds of hardware the function
46 * STP_OUT_flush_lt is a) is very hard and b) cannot
47 * delete learning emtries per port. The alternate
48 * method may be used: we don't care operEdge flag here,
49 * but clean learning table once for TopologyChange
50 * for all ports, except the received port. I am ready to discuss :(
51 * See below word STRONGLY_SPEC_802_1W
55 flush (STATE_MACH_T
*this, char* reason
) /* 17.19.9 */
57 register PORT_T
* port
= this->owner
.port
;
60 if (port
->operEdge
) return True
;
62 stp_trace("%s (%s, %s, %s, '%s')",
63 "flush", port
->port_name
, port
->owner
->name
,
64 LT_FLASH_ONLY_THE_PORT
== type
? "this port" : "other ports",
68 bret
= STP_OUT_flush_lt (port
->port_index
, port
->owner
->vlan_id
,
69 LT_FLASH_ONLY_THE_PORT
, reason
);
74 setTcPropBridge (STATE_MACH_T
* this, char* reason
) /* 17.19.14 */
76 register PORT_T
* port
= this->owner
.port
;
79 for (tmp
= port
->owner
->ports
; tmp
; tmp
= tmp
->next
) {
80 if (tmp
->port_index
!= port
->port_index
)
84 #ifndef STRONGLY_SPEC_802_1W
87 stp_trace("%s (%s, %s, %s, '%s')",
88 "clearFDB", port
->port_name
, port
->owner
->name
,
89 "other ports", reason
);
93 STP_OUT_flush_lt (port
->port_index
, port
->owner
->vlan_id
,
94 LT_FLASH_ALL_PORTS_EXCLUDE_THIS
, reason
);
99 newTcWhile (STATE_MACH_T
* this) /* 17.19.7 */
101 register PORT_T
* port
= this->owner
.port
;
103 if (port
->sendRSTP
&& port
->operPointToPointMac
) {
104 return 2 * port
->owner
->rootTimes
.HelloTime
;
106 return port
->owner
->rootTimes
.MaxAge
;
110 STP_topoch_enter_state (STATE_MACH_T
* this)
112 register PORT_T
* port
= this->owner
.port
;
114 switch (this->State
) {
117 #ifdef STRONGLY_SPEC_802_1W
118 flush (this, "topoch INIT");
128 port
->rcvdTcAck
= port
->tc
= port
->tcProp
= False
;
133 port
->tcWhile
= newTcWhile (this);
136 stp_trace("DETECTED: tcWhile=%d on port %s",
137 port
->tcWhile
, port
->port_name
);
139 setTcPropBridge (this, "DETECTED");
143 port
->rcvdTcn
= port
->rcvdTc
= False
;
144 if (port
->role
== DesignatedPort
) {
147 setTcPropBridge (this, "NOTIFIED_TC");
150 port
->tcWhile
= newTcWhile (this);
153 stp_trace("PROPAGATING: tcWhile=%d on port %s",
154 port
->tcWhile
, port
->port_name
);
156 #ifdef STRONGLY_SPEC_802_1W
157 flush (this, "topoch PROPAGATING");
159 port
->tcProp
= False
;
165 stp_trace("ACKNOWLEDGED: tcWhile=%d on port %s",
166 port
->tcWhile
, port
->port_name
);
168 port
->rcvdTcAck
= False
;
171 port
->tcWhile
= newTcWhile (this);
174 stp_trace("NOTIFIED_TCN: tcWhile=%d on port %s",
175 port
->tcWhile
, port
->port_name
);
182 STP_topoch_check_conditions (STATE_MACH_T
* this)
184 register PORT_T
* port
= this->owner
.port
;
186 if (BEGIN
== this->State
) {
187 return STP_hop_2_state (this, INIT
);
190 switch (this->State
) {
192 return STP_hop_2_state (this, INACTIVE
);
194 if (port
->role
== RootPort
|| port
->role
== DesignatedPort
)
195 return STP_hop_2_state (this, TCACTIVE
);
196 if (port
->rcvdTc
|| port
->rcvdTcn
|| port
->rcvdTcAck
||
197 port
->tc
|| port
->tcProp
)
198 return STP_hop_2_state (this, INACTIVE
);
201 if (port
->role
!= RootPort
&& (port
->role
!= DesignatedPort
))
202 return STP_hop_2_state (this, INIT
);
204 return STP_hop_2_state (this, DETECTED
);
206 return STP_hop_2_state (this, NOTIFIED_TCN
);
208 return STP_hop_2_state (this, NOTIFIED_TC
);
209 if (port
->tcProp
&& !port
->operEdge
)
210 return STP_hop_2_state (this, PROPAGATING
);
212 return STP_hop_2_state (this, ACKNOWLEDGED
);
215 return STP_hop_2_state (this, TCACTIVE
);
217 return STP_hop_2_state (this, TCACTIVE
);
219 return STP_hop_2_state (this, TCACTIVE
);
221 return STP_hop_2_state (this, TCACTIVE
);
223 return STP_hop_2_state (this, NOTIFIED_TC
);