8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / librstp / common / rolesel.c
blob871622d354873a8f0fa55f3eb48e62b78890ca04
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 Selection state machine : 17.22 */
25 #include "base.h"
26 #include "stpm.h"
27 #include "stp_vectors.h"
29 #define STATES { \
30 CHOOSE(INIT_BRIDGE), \
31 CHOOSE(ROLE_SELECTION) \
34 #define GET_STATE_NAME STP_rolesel_get_state_name
35 #include "choose.h"
37 #if 0
38 void stp_dbg_break_point (PORT_T * port, STPM_T* stpm)
41 #endif
43 static Bool
44 _is_backup_port (PORT_T* port, STPM_T* this)
46 if (!STP_VECT_compare_bridge_id
47 (&port->portPrio.design_bridge, &this->BrId)) {
48 #if 0 /* def STP_DBG */
49 if (port->info->debug) {
50 STP_VECT_br_id_print ("portPrio.design_bridge",
51 &port->portPrio.design_bridge, True);
52 STP_VECT_br_id_print (" this->BrId",
53 &this->BrId, True);
55 stp_dbg_break_point (port, this);
56 #endif
57 return True;
58 } else {
59 return False;
63 /* ARGSUSED */
64 static void
65 setRoleSelected (char* reason, STPM_T* stpm, PORT_T* port,
66 PORT_ROLE_T newRole)
68 #ifdef STP_DBG
69 char* new_role_name;
70 #endif
72 port->selectedRole = newRole;
74 if (newRole == port->role)
75 return;
77 switch (newRole) {
78 case DisabledPort:
79 #ifdef STP_DBG
80 new_role_name = "Disabled";
81 #endif
82 break;
83 case AlternatePort:
84 #ifdef STP_DBG
85 new_role_name = "Alternate";
86 #endif
87 break;
88 case BackupPort:
89 #ifdef STP_DBG
90 new_role_name = "Backup";
91 #endif
92 break;
93 case RootPort:
94 #ifdef STP_DBG
95 new_role_name = "Root";
96 #endif
97 break;
98 case DesignatedPort:
99 #ifdef STP_DBG
100 new_role_name = "Designated";
101 #endif
102 break;
103 case NonStpPort:
104 #ifdef STP_DBG
105 new_role_name = "NonStp";
106 #endif
107 port->role = newRole;
108 break;
109 default:
110 #ifdef STP_DBG
111 stp_trace ("%s-%s:port %s => Unknown (%d ?)",
112 reason, stpm->name, port->port_name, (int) newRole);
113 #else
114 abort();
115 #endif
116 return;
119 #ifdef STP_DBG
120 if (port->roletrns->debug)
121 stp_trace ("%s(%s-%s) => %s",
122 reason, stpm->name, port->port_name, new_role_name);
123 #endif
126 static void
127 updtRoleDisableBridge (STPM_T* this)
128 { /* 17.10.20 */
129 register PORT_T *port;
131 for (port = this->ports; port; port = port->next) {
132 port->selectedRole = DisabledPort;
136 static void
137 clearReselectBridge (STPM_T* this)
138 { /* 17.19.1 */
139 register PORT_T *port;
141 for (port = this->ports; port; port = port->next) {
142 port->reselect = False;
146 static void
147 updtRootPrio (STATE_MACH_T* this)
149 PRIO_VECTOR_T rootPathPrio; /* 17.4.2.2 */
150 register PORT_T *port;
151 register STPM_T *stpm;
152 register unsigned int dm;
154 stpm = this->owner.stpm;
156 for (port = stpm->ports; port; port = port->next) {
157 if (port->admin_non_stp) {
158 continue;
161 if (Disabled == port->infoIs)
162 continue;
163 if (Aged == port->infoIs)
164 continue;
165 if (Mine == port->infoIs) {
166 #if 0 /* def STP_DBG */
167 stp_dbg_break_point (port); /* for debugger break point */
168 #endif
169 continue;
172 STP_VECT_copy (&rootPathPrio, &port->portPrio);
173 rootPathPrio.root_path_cost += port->operPCost;
175 if (STP_VECT_compare_vector (&rootPathPrio, &stpm->rootPrio) < 0) {
176 STP_VECT_copy (&stpm->rootPrio, &rootPathPrio);
177 STP_copy_times (&stpm->rootTimes, &port->portTimes);
178 dm = (8 + stpm->rootTimes.MaxAge) / 16;
179 if (!dm)
180 dm = 1;
181 stpm->rootTimes.MessageAge += dm;
182 #ifdef STP_DBG
183 if (port->roletrns->debug)
184 stp_trace ("updtRootPrio: dm=%d rootTimes.MessageAge=%d on port %s",
185 (int) dm, (int) stpm->rootTimes.MessageAge,
186 port->port_name);
187 #endif
192 static void
193 updtRolesBridge (STATE_MACH_T* this)
194 { /* 17.19.21 */
195 register PORT_T* port;
196 register STPM_T* stpm;
197 #ifdef STP_DBG
198 PORT_ID old_root_port; /* for tracing of root port changing */
199 #endif
201 stpm = this->owner.stpm;
202 #ifdef STP_DBG
203 old_root_port = stpm->rootPortId;
204 #endif
206 STP_VECT_create (&stpm->rootPrio, &stpm->BrId, 0, &stpm->BrId, 0, 0);
207 STP_copy_times (&stpm->rootTimes, &stpm->BrTimes);
208 stpm->rootPortId = 0;
210 updtRootPrio (this);
212 for (port = stpm->ports; port; port = port->next) {
213 if (port->admin_non_stp) {
214 continue;
216 STP_VECT_create (&port->designPrio,
217 &stpm->rootPrio.root_bridge,
218 stpm->rootPrio.root_path_cost,
219 &stpm->BrId, port->port_id, port->port_id);
220 STP_copy_times (&port->designTimes, &stpm->rootTimes);
222 #if 0
223 #ifdef STP_DBG
224 if (port->roletrns->debug) {
225 STP_VECT_br_id_print ("ch:designPrio.design_bridge",
226 &port->designPrio.design_bridge, True);
228 #endif
229 #endif
232 stpm->rootPortId = stpm->rootPrio.bridge_port;
234 #ifdef STP_DBG
235 if (old_root_port != stpm->rootPortId) {
236 if (! stpm->rootPortId) {
237 stp_trace ("bridge %s became root", stpm->name);
238 } else {
239 stp_trace ("bridge %s new root port: %s",
240 stpm->name,
241 STP_stpm_get_port_name_by_id (stpm, stpm->rootPortId));
244 #endif
246 for (port = stpm->ports; port; port = port->next) {
247 if (port->admin_non_stp) {
248 setRoleSelected ("Non", stpm, port, NonStpPort);
249 port->forward = port->learn = True;
250 continue;
253 switch (port->infoIs) {
254 case Disabled:
255 setRoleSelected ("Dis", stpm, port, DisabledPort);
256 break;
257 case Aged:
258 setRoleSelected ("Age", stpm, port, DesignatedPort);
259 port->updtInfo = True;
260 break;
261 case Mine:
262 setRoleSelected ("Mine", stpm, port, DesignatedPort);
263 if (0 != STP_VECT_compare_vector (&port->portPrio,
264 &port->designPrio) ||
265 0 != STP_compare_times (&port->portTimes,
266 &port->designTimes)) {
267 port->updtInfo = True;
269 break;
270 case Received:
271 if (stpm->rootPortId == port->port_id) {
272 setRoleSelected ("Rec", stpm, port, RootPort);
273 } else if (STP_VECT_compare_vector (&port->designPrio, &port->portPrio) < 0) {
274 /* Note: this important piece has been inserted after
275 * discussion with Mick Sieman and reading 802.1y Z1 */
276 setRoleSelected ("Rec", stpm, port, DesignatedPort);
277 port->updtInfo = True;
278 break;
279 } else {
280 if (_is_backup_port (port, stpm)) {
281 setRoleSelected ("rec", stpm, port, BackupPort);
282 } else {
283 setRoleSelected ("rec", stpm, port, AlternatePort);
286 port->updtInfo = False;
287 break;
288 default:
289 stp_trace ("undef infoIs=%d", (int) port->infoIs);
290 break;
297 static Bool
298 setSelectedBridge (STPM_T* this)
300 register PORT_T* port;
302 for (port = this->ports; port; port = port->next) {
303 if (port->reselect) {
304 #ifdef STP_DBG
305 stp_trace ("setSelectedBridge: TRUE=reselect on port %s", port->port_name);
306 #endif
307 return False;
311 for (port = this->ports; port; port = port->next) {
312 port->selected = True;
315 return True;
318 void
319 STP_rolesel_enter_state (STATE_MACH_T* this)
321 STPM_T* stpm;
323 stpm = this->owner.stpm;
325 switch (this->State) {
326 case BEGIN:
327 case INIT_BRIDGE:
328 updtRoleDisableBridge (stpm);
329 break;
330 case ROLE_SELECTION:
331 clearReselectBridge (stpm);
332 updtRolesBridge (this);
333 (void) setSelectedBridge (stpm);
334 break;
338 Bool
339 STP_rolesel_check_conditions (STATE_MACH_T* s)
341 STPM_T* stpm;
342 register PORT_T* port;
345 * This doesn't look right. Why should we hop state twice in a single check
346 * condition call? It means we can never perform the enter-state action for
347 * INIT_BRIDGE.
349 #ifdef carlsonj_removed
350 if (BEGIN == s->State) {
351 (void) STP_hop_2_state (s, INIT_BRIDGE);
353 #endif
355 switch (s->State) {
356 case BEGIN:
357 return STP_hop_2_state (s, INIT_BRIDGE);
358 case INIT_BRIDGE:
359 return STP_hop_2_state (s, ROLE_SELECTION);
360 case ROLE_SELECTION:
361 stpm = s->owner.stpm;
362 for (port = stpm->ports; port; port = port->next) {
363 if (port->reselect) {
364 /* stp_trace ("reselect on port %s", port->port_name); */
365 return STP_hop_2_state (s, ROLE_SELECTION);
368 break;
371 return False;
374 void
375 STP_rolesel_update_stpm (STPM_T* this)
377 register PORT_T* port;
378 PRIO_VECTOR_T rootPathPrio; /* 17.4.2.2 */
380 stp_trace ("%s", "??? STP_rolesel_update_stpm ???");
381 STP_VECT_create (&rootPathPrio, &this->BrId, 0, &this->BrId, 0, 0);
383 if (!this->rootPortId ||
384 STP_VECT_compare_vector (&rootPathPrio, &this->rootPrio) < 0) {
385 STP_VECT_copy (&this->rootPrio, &rootPathPrio);
388 for (port = this->ports; port; port = port->next) {
389 STP_VECT_create (&port->designPrio,
390 &this->rootPrio.root_bridge,
391 this->rootPrio.root_path_cost,
392 &this->BrId, port->port_id, port->port_id);
393 if (Received != port->infoIs || this->rootPortId == port->port_id) {
394 STP_VECT_copy (&port->portPrio, &port->designPrio);
396 port->reselect = True;
397 port->selected = False;