dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / librstp / common / roletrns.c
blobd6684d39581f7e65c054872ea1ba433d92ddd38c
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
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
20 * 02111-1307, USA.
21 **********************************************************************/
23 /* Port Role Transitions state machine : 17.24 */
25 #include "base.h"
27 #include "stpm.h"
29 #define STATES { \
30 CHOOSE(INIT_PORT), \
31 CHOOSE(BLOCK_PORT), \
32 CHOOSE(BLOCKED_PORT), \
33 CHOOSE(BACKUP_PORT), \
34 CHOOSE(ROOT_PROPOSED), \
35 CHOOSE(ROOT_AGREED), \
36 CHOOSE(REROOT), \
37 CHOOSE(ROOT_PORT), \
38 CHOOSE(REROOTED), \
39 CHOOSE(ROOT_LEARN), \
40 CHOOSE(ROOT_FORWARD), \
41 CHOOSE(DESIGNATED_PROPOSE), \
42 CHOOSE(DESIGNATED_SYNCED), \
43 CHOOSE(DESIGNATED_RETIRED), \
44 CHOOSE(DESIGNATED_PORT), \
45 CHOOSE(DESIGNATED_LISTEN), \
46 CHOOSE(DESIGNATED_LEARN), \
47 CHOOSE(DESIGNATED_FORWARD) \
50 #define GET_STATE_NAME STP_roletrns_get_state_name
51 #include "choose.h"
53 static void
54 setSyncBridge (STATE_MACH_T *this)
56 register PORT_T* port;
58 for (port = this->owner.port->owner->ports; port; port = port->next) {
59 port->sync = True; /* in ROOT_PROPOSED (setSyncBridge) */
63 static void
64 setReRootBridge (STATE_MACH_T *this)
66 register PORT_T* port;
68 for (port = this->owner.port->owner->ports; port; port = port->next) {
69 port->reRoot = True; /* In setReRootBridge */
73 static Bool
74 compute_all_synced (PORT_T* this)
76 register PORT_T* port;
78 for (port = this->owner->ports; port; port = port->next) {
79 if (port->port_index == this->port_index) continue;
80 if (! port->synced) {
81 return False;
85 return True;
88 static Bool
89 compute_re_rooted (PORT_T* this)
91 register PORT_T* port;
93 for (port = this->owner->ports; port; port = port->next) {
94 if (port->port_index == this->port_index) continue;
95 if (port->rrWhile) {
96 return False;
99 return True;
102 void
103 STP_roletrns_enter_state (STATE_MACH_T* this)
105 register PORT_T* port = this->owner.port;
106 register STPM_T* stpm;
108 stpm = port->owner;
110 switch (this->State) {
111 case BEGIN:
112 case INIT_PORT:
113 #if 0 /* due 802.1y Z.4 */
114 port->role = DisabledPort;
115 #else
116 port->role = port->selectedRole = DisabledPort;
117 port->reselect = True;
118 #endif
119 port->synced = False; /* in INIT */
120 port->sync = True; /* in INIT */
121 port->reRoot = True; /* in INIT_PORT */
122 port->rrWhile = stpm->rootTimes.ForwardDelay;
123 port->fdWhile = stpm->rootTimes.ForwardDelay;
124 port->rbWhile = 0;
125 #ifdef STP_DBG
126 if (this->debug)
127 STP_port_trace_flags ("after init", port);
128 #endif
129 break;
130 case BLOCK_PORT:
131 port->role = port->selectedRole;
132 port->learn =
133 port->forward = False;
134 break;
135 case BLOCKED_PORT:
136 port->fdWhile = stpm->rootTimes.ForwardDelay;
137 port->synced = True; /* In BLOCKED_PORT */
138 port->rrWhile = 0;
139 port->sync = port->reRoot = False; /* BLOCKED_PORT */
140 break;
141 case BACKUP_PORT:
142 port->rbWhile = 2 * stpm->rootTimes.HelloTime;
143 break;
145 /* 17.23.2 */
146 case ROOT_PROPOSED:
147 setSyncBridge (this);
148 port->proposed = False;
149 #ifdef STP_DBG
150 if (this->debug)
151 STP_port_trace_flags ("ROOT_PROPOSED", port);
152 #endif
153 break;
154 case ROOT_AGREED:
155 port->proposed = port->sync = False; /* in ROOT_AGREED */
156 port->synced = True; /* In ROOT_AGREED */
157 port->newInfo = True;
158 #ifdef STP_DBG
159 if (this->debug)
160 STP_port_trace_flags ("ROOT_AGREED", port);
161 #endif
162 break;
163 case REROOT:
164 setReRootBridge (this);
165 #ifdef STP_DBG
166 if (this->debug)
167 STP_port_trace_flags ("REROOT", port);
168 #endif
169 break;
170 case ROOT_PORT:
171 port->role = RootPort;
172 port->rrWhile = stpm->rootTimes.ForwardDelay;
173 #ifdef STP_DBG
174 if (this->debug)
175 STP_port_trace_flags ("ROOT_PORT", port);
176 #endif
177 break;
178 case REROOTED:
179 port->reRoot = False; /* In REROOTED */
180 #ifdef STP_DBG
181 if (this->debug)
182 STP_port_trace_flags ("REROOTED", port);
183 #endif
184 break;
185 case ROOT_LEARN:
186 port->fdWhile = stpm->rootTimes.ForwardDelay;
187 port->learn = True;
188 #ifdef STP_DBG
189 if (this->debug)
190 STP_port_trace_flags ("ROOT_LEARN", port);
191 #endif
192 break;
193 case ROOT_FORWARD:
194 port->fdWhile = 0;
195 port->forward = True;
196 #ifdef STP_DBG
197 if (this->debug)
198 STP_port_trace_flags ("ROOT_FORWARD", port);
199 #endif
200 break;
202 /* 17.23.3 */
203 case DESIGNATED_PROPOSE:
204 port->proposing = True; /* in DESIGNATED_PROPOSE */
205 port->newInfo = True;
206 #ifdef STP_DBG
207 if (this->debug)
208 STP_port_trace_flags ("DESIGNATED_PROPOSE", port);
209 #endif
210 break;
211 case DESIGNATED_SYNCED:
212 port->rrWhile = 0;
213 port->synced = True; /* DESIGNATED_SYNCED */
214 port->sync = False; /* DESIGNATED_SYNCED */
215 #ifdef STP_DBG
216 if (this->debug)
217 STP_port_trace_flags ("DESIGNATED_SYNCED", port);
218 #endif
219 break;
220 case DESIGNATED_RETIRED:
221 port->reRoot = False; /* DESIGNATED_RETIRED */
222 #ifdef STP_DBG
223 if (this->debug)
224 STP_port_trace_flags ("DESIGNATED_RETIRED", port);
225 #endif
226 break;
227 case DESIGNATED_PORT:
228 port->role = DesignatedPort;
229 #ifdef STP_DBG
230 if (this->debug)
231 STP_port_trace_flags ("DESIGNATED_PORT", port);
232 #endif
233 break;
234 case DESIGNATED_LISTEN:
235 port->learn = port->forward = False;
236 port->fdWhile = stpm->rootTimes.ForwardDelay;
237 #ifdef STP_DBG
238 if (this->debug)
239 STP_port_trace_flags ("DESIGNATED_LISTEN", port);
240 #endif
241 break;
242 case DESIGNATED_LEARN:
243 port->learn = True;
244 port->fdWhile = stpm->rootTimes.ForwardDelay;
245 #ifdef STP_DBG
246 if (this->debug)
247 STP_port_trace_flags ("DESIGNATED_LEARN", port);
248 #endif
249 break;
250 case DESIGNATED_FORWARD:
251 port->forward = True;
252 port->fdWhile = 0;
253 #ifdef STP_DBG
254 if (this->debug)
255 STP_port_trace_flags ("DESIGNATED_FORWARD", port);
256 #endif
257 break;
261 Bool
262 STP_roletrns_check_conditions (STATE_MACH_T* this)
264 register PORT_T *port = this->owner.port;
265 register STPM_T *stpm;
266 Bool allSynced;
267 Bool allReRooted;
269 stpm = port->owner;
271 if (BEGIN == this->State) {
272 return STP_hop_2_state (this, INIT_PORT);
275 if (port->role != port->selectedRole &&
276 port->selected &&
277 ! port->updtInfo) {
278 switch (port->selectedRole) {
279 case DisabledPort:
280 case AlternatePort:
281 case BackupPort:
282 #if 0 /* def STP_DBG */
283 if (this->debug) {
284 stp_trace ("hop to BLOCK_PORT role=%d selectedRole=%d",
285 (int) port->role, (int) port->selectedRole);
287 #endif
288 return STP_hop_2_state (this, BLOCK_PORT);
289 case RootPort:
290 return STP_hop_2_state (this, ROOT_PORT);
291 case DesignatedPort:
292 return STP_hop_2_state (this, DESIGNATED_PORT);
293 default:
294 return False;
298 switch (this->State) {
299 /* 17.23.1 */
300 case INIT_PORT:
301 return STP_hop_2_state (this, BLOCK_PORT);
302 case BLOCK_PORT:
303 if (!port->selected || port->updtInfo) break;
304 if (!port->learning && !port->forwarding) {
305 return STP_hop_2_state (this, BLOCKED_PORT);
307 break;
308 case BLOCKED_PORT:
309 if (!port->selected || port->updtInfo) break;
310 if (port->fdWhile != stpm->rootTimes.ForwardDelay ||
311 port->sync ||
312 port->reRoot ||
313 !port->synced) {
314 return STP_hop_2_state (this, BLOCKED_PORT);
316 if (port->rbWhile != 2 * stpm->rootTimes.HelloTime &&
317 port->role == BackupPort) {
318 return STP_hop_2_state (this, BACKUP_PORT);
320 break;
321 case BACKUP_PORT:
322 return STP_hop_2_state (this, BLOCKED_PORT);
324 /* 17.23.2 */
325 case ROOT_PROPOSED:
326 return STP_hop_2_state (this, ROOT_PORT);
327 case ROOT_AGREED:
328 return STP_hop_2_state (this, ROOT_PORT);
329 case REROOT:
330 return STP_hop_2_state (this, ROOT_PORT);
331 case ROOT_PORT:
332 if (!port->selected || port->updtInfo) break;
333 if (!port->forward && !port->reRoot) {
334 return STP_hop_2_state (this, REROOT);
336 allSynced = compute_all_synced (port);
337 if ((port->proposed && allSynced) ||
338 (!port->synced && allSynced)) {
339 return STP_hop_2_state (this, ROOT_AGREED);
341 if (port->proposed && !port->synced) {
342 return STP_hop_2_state (this, ROOT_PROPOSED);
345 allReRooted = compute_re_rooted (port);
346 if ((!port->fdWhile ||
347 ((allReRooted && !port->rbWhile) && stpm->ForceVersion >=2)) &&
348 port->learn && !port->forward) {
349 return STP_hop_2_state (this, ROOT_FORWARD);
351 if ((!port->fdWhile ||
352 ((allReRooted && !port->rbWhile) && stpm->ForceVersion >=2)) &&
353 !port->learn) {
354 return STP_hop_2_state (this, ROOT_LEARN);
357 if (port->reRoot && port->forward) {
358 return STP_hop_2_state (this, REROOTED);
360 if (port->rrWhile != stpm->rootTimes.ForwardDelay) {
361 return STP_hop_2_state (this, ROOT_PORT);
363 break;
364 case REROOTED:
365 return STP_hop_2_state (this, ROOT_PORT);
366 case ROOT_LEARN:
367 return STP_hop_2_state (this, ROOT_PORT);
368 case ROOT_FORWARD:
369 return STP_hop_2_state (this, ROOT_PORT);
371 /* 17.23.3 */
372 case DESIGNATED_PROPOSE:
373 return STP_hop_2_state (this, DESIGNATED_PORT);
374 case DESIGNATED_SYNCED:
375 return STP_hop_2_state (this, DESIGNATED_PORT);
376 case DESIGNATED_RETIRED:
377 return STP_hop_2_state (this, DESIGNATED_PORT);
378 case DESIGNATED_PORT:
379 if (!port->selected || port->updtInfo) break;
381 if (!port->forward && !port->agreed && !port->proposing && !port->operEdge) {
382 return STP_hop_2_state (this, DESIGNATED_PROPOSE);
385 if (!port->rrWhile && port->reRoot) {
386 return STP_hop_2_state (this, DESIGNATED_RETIRED);
389 if (!port->learning && !port->forwarding && !port->synced) {
390 return STP_hop_2_state (this, DESIGNATED_SYNCED);
393 if (port->agreed && !port->synced) {
394 return STP_hop_2_state (this, DESIGNATED_SYNCED);
396 if (port->operEdge && !port->synced) {
397 return STP_hop_2_state (this, DESIGNATED_SYNCED);
399 if (port->sync && port->synced) {
400 return STP_hop_2_state (this, DESIGNATED_SYNCED);
403 if ((!port->fdWhile || port->agreed || port->operEdge) &&
404 (!port->rrWhile || !port->reRoot) &&
405 !port->sync &&
406 (port->learn && !port->forward)) {
407 return STP_hop_2_state (this, DESIGNATED_FORWARD);
409 if ((!port->fdWhile || port->agreed || port->operEdge) &&
410 (!port->rrWhile || !port->reRoot) &&
411 !port->sync && !port->learn) {
412 return STP_hop_2_state (this, DESIGNATED_LEARN);
414 if (((port->sync && !port->synced) ||
415 (port->reRoot && port->rrWhile)) &&
416 !port->operEdge && (port->learn || port->forward)) {
417 return STP_hop_2_state (this, DESIGNATED_LISTEN);
419 break;
420 case DESIGNATED_LISTEN:
421 return STP_hop_2_state (this, DESIGNATED_PORT);
422 case DESIGNATED_LEARN:
423 return STP_hop_2_state (this, DESIGNATED_PORT);
424 case DESIGNATED_FORWARD:
425 return STP_hop_2_state (this, DESIGNATED_PORT);
428 return False;