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 /* We can flush learned fdb by port, so set this in stpm.c and topoch.c */
44 /* This doesn't seem to solve the topology change problems. Don't use it yet */
45 //#define STRONGLY_SPEC_802_1W
47 #ifndef STRONGLY_SPEC_802_1W
49 * In many kinds of hardware the function
50 * STP_OUT_flush_lt is a) is very hard and b) cannot
51 * delete learning emtries per port. The alternate
52 * method may be used: we don't care operEdge flag here,
53 * but clean learning table once for TopologyChange
54 * for all ports, except the received port. I am ready to discuss :(
55 * See below word STRONGLY_SPEC_802_1W
59 flush (STATE_MACH_T
*this, char* reason
) /* 17.19.9 */
61 register PORT_T
* port
= this->owner
.port
;
64 if (port
->operEdge
) return True
;
66 stp_trace("%s (%s, %s, %s, '%s')",
67 "flush", port
->port_name
, port
->owner
->name
,
72 bret
= STP_OUT_flush_lt (port
->port_index
, port
->owner
->vlan_id
,
73 LT_FLASH_ONLY_THE_PORT
, reason
);
79 setTcPropBridge (STATE_MACH_T
* this, char* reason
) /* 17.19.14 */
81 register PORT_T
* port
= this->owner
.port
;
84 for (tmp
= port
->owner
->ports
; tmp
; tmp
= tmp
->next
) {
85 if (tmp
->port_index
!= port
->port_index
)
89 #ifndef STRONGLY_SPEC_802_1W
92 stp_trace("%s (%s, %s, %s, '%s')",
93 "clearFDB", port
->port_name
, port
->owner
->name
,
94 "other ports", reason
);
98 STP_OUT_flush_lt (port
->port_index
, port
->owner
->vlan_id
,
99 LT_FLASH_ALL_PORTS_EXCLUDE_THIS
, reason
);
104 newTcWhile (STATE_MACH_T
* this) /* 17.19.7 */
106 register PORT_T
* port
= this->owner
.port
;
108 if (port
->sendRSTP
&& port
->operPointToPointMac
) {
109 return 2 * port
->owner
->rootTimes
.HelloTime
;
112 return port
->owner
->rootTimes
.MaxAge
;
114 return port
->owner
->rootTimes
.MaxAge
+ port
->owner
->rootTimes
.ForwardDelay
;
119 STP_topoch_enter_state (STATE_MACH_T
* this)
121 register PORT_T
* port
= this->owner
.port
;
123 switch (this->State
) {
126 #ifdef STRONGLY_SPEC_802_1W
127 flush (this, "topoch INIT");
137 port
->rcvdTcAck
= port
->tc
= port
->tcProp
= False
;
142 port
->tcWhile
= newTcWhile (this);
145 stp_trace("DETECTED: tcWhile=%d on port %s",
146 port
->tcWhile
, port
->port_name
);
148 setTcPropBridge (this, "DETECTED");
152 port
->rcvdTcn
= port
->rcvdTc
= False
;
153 if (port
->role
== DesignatedPort
) {
156 setTcPropBridge (this, "NOTIFIED_TC");
159 port
->tcWhile
= newTcWhile (this);
162 stp_trace("PROPAGATING: tcWhile=%d on port %s",
163 port
->tcWhile
, port
->port_name
);
165 #ifdef STRONGLY_SPEC_802_1W
166 flush (this, "topoch PROPAGATING");
168 port
->tcProp
= False
;
174 stp_trace("ACKNOWLEDGED: tcWhile=%d on port %s",
175 port
->tcWhile
, port
->port_name
);
177 port
->rcvdTcAck
= False
;
180 port
->tcWhile
= newTcWhile (this);
183 stp_trace("NOTIFIED_TCN: tcWhile=%d on port %s",
184 port
->tcWhile
, port
->port_name
);
191 STP_topoch_check_conditions (STATE_MACH_T
* this)
193 register PORT_T
* port
= this->owner
.port
;
195 if (BEGIN
== this->State
) {
196 return STP_hop_2_state (this, INIT
);
199 switch (this->State
) {
201 return STP_hop_2_state (this, INACTIVE
);
203 if (port
->role
== RootPort
|| port
->role
== DesignatedPort
)
204 return STP_hop_2_state (this, TCACTIVE
);
205 if (port
->rcvdTc
|| port
->rcvdTcn
|| port
->rcvdTcAck
||
206 port
->tc
|| port
->tcProp
)
207 return STP_hop_2_state (this, INACTIVE
);
210 if (port
->role
!= RootPort
&& (port
->role
!= DesignatedPort
))
211 return STP_hop_2_state (this, INIT
);
213 return STP_hop_2_state (this, DETECTED
);
215 return STP_hop_2_state (this, NOTIFIED_TCN
);
217 return STP_hop_2_state (this, NOTIFIED_TC
);
218 if (port
->tcProp
&& !port
->operEdge
)
219 return STP_hop_2_state (this, PROPAGATING
);
221 return STP_hop_2_state (this, ACKNOWLEDGED
);
224 return STP_hop_2_state (this, TCACTIVE
);
226 return STP_hop_2_state (this, TCACTIVE
);
228 return STP_hop_2_state (this, TCACTIVE
);
230 return STP_hop_2_state (this, TCACTIVE
);
232 return STP_hop_2_state (this, NOTIFIED_TC
);