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 /* STP machine instance : bridge per VLAN: 17.17 */
27 #include "stp_to.h" /* for STP_OUT_flush_lt */
29 static STPM_T
*bridges
= NULL
;
32 _stp_stpm_init_machine (STATE_MACH_T
* this)
35 (*(this->concreteEnterState
)) (this);
40 _stp_stpm_iterate_machines (STPM_T
* this,
41 int (*iter_callb
) (STATE_MACH_T
*),
42 Bool exit_on_non_zero_ret
)
44 register STATE_MACH_T
* stater
;
45 register PORT_T
* port
;
48 /* state machines per bridge */
49 for (stater
= this->machines
; stater
; stater
= stater
->next
) {
50 iret
= (*iter_callb
) (stater
);
51 if (exit_on_non_zero_ret
&& iret
)
57 /* state machines per port */
58 for (port
= this->ports
; port
; port
= port
->next
) {
59 for (stater
= port
->machines
; stater
; stater
= stater
->next
) {
60 iret
= (*iter_callb
) (stater
);
61 if (exit_on_non_zero_ret
&& iret
)
72 _stp_stpm_init_data (STPM_T
* this)
74 STP_VECT_create (&this->rootPrio
,
80 this->BrTimes
.MessageAge
= 0;
82 STP_copy_times (&this->rootTimes
, &this->BrTimes
);
86 _check_topoch (STPM_T
* this)
88 register PORT_T
* port
;
90 for (port
= this->ports
; port
; port
= port
->next
) {
99 STP_stpm_one_second (STPM_T
* param
)
101 STPM_T
* this = (STPM_T
*) param
;
102 register PORT_T
* port
;
105 if (STP_ENABLED
!= this->admin_state
) return;
107 for (port
= this->ports
; port
; port
= port
->next
) {
108 for (iii
= 0; iii
< TIMERS_NUMBER
; iii
++) {
109 if (*(port
->timers
[iii
]) > 0) {
110 (*port
->timers
[iii
])--;
116 (void) STP_stpm_update (this);
117 this->Topo_Change
= _check_topoch (this);
118 if (this->Topo_Change
) {
119 this->Topo_Change_Count
++;
120 this->timeSince_Topo_Change
= 0;
122 this->Topo_Change_Count
= 0;
123 this->timeSince_Topo_Change
++;
128 STP_stpm_create (int vlan_id
, char* name
)
132 STP_NEW_IN_LIST(this, STPM_T
, bridges
, "stp instance");
134 this->admin_state
= STP_DISABLED
;
136 this->vlan_id
= vlan_id
;
138 STP_STRDUP(this->name
, name
, "stp bridge name");
141 this->machines
= NULL
;
144 STP_STATE_MACH_IN_LIST(rolesel
);
147 /* this->rolesel->debug = 2; */
154 STP_stpm_enable (STPM_T
* this, UID_STP_MODE_T admin_state
)
158 if (admin_state
== this->admin_state
) {
159 /* nothing to do :) */
163 if (STP_ENABLED
== admin_state
) {
165 rc
= STP_stpm_start (this);
166 this->admin_state
= admin_state
;
168 this->admin_state
= admin_state
;
169 STP_stpm_stop (this);
176 STP_stpm_delete (STPM_T
* this)
178 register STPM_T
* tmp
;
179 register STPM_T
* prev
;
180 register STATE_MACH_T
* stater
;
181 register PORT_T
* port
;
184 (void) STP_stpm_enable (this, STP_DISABLED
);
186 for (stater
= this->machines
; stater
; ) {
187 pv
= (void*) stater
->next
;
188 STP_state_mach_delete (stater
);
189 this->machines
= stater
= (STATE_MACH_T
*) pv
;
192 for (port
= this->ports
; port
; ) {
193 pv
= (void*) port
->next
;
194 STP_port_delete (port
);
195 this->ports
= port
= (PORT_T
*) pv
;
199 for (tmp
= bridges
; tmp
; tmp
= tmp
->next
) {
200 if (tmp
->vlan_id
== this->vlan_id
) {
202 prev
->next
= this->next
;
204 bridges
= this->next
;
208 STP_FREE(this->name
, "stp bridge name");
209 STP_FREE(this, "stp instance");
217 STP_stpm_start (STPM_T
* this)
219 register PORT_T
* port
;
221 if (! this->ports
) { /* there are not any ports :( */
222 return STP_There_Are_No_Ports
;
225 if (! STP_compute_bridge_id (this)) {/* can't compute bridge id ? :( */
226 return STP_Cannot_Compute_Bridge_Prio
;
229 /* check, that the stpm has unique bridge Id */
230 if (0 != STP_stpm_check_bridge_priority (this)) {
231 /* there is an enabled bridge with same ID :( */
232 return STP_Invalid_Bridge_Priority
;
235 _stp_stpm_init_data (this);
237 for (port
= this->ports
; port
; port
= port
->next
) {
238 STP_port_init (port
, this, True
);
241 #ifndef STRONGLY_SPEC_802_1W
242 /* A. see comment near STRONGLY_SPEC_802_1W in topoch.c */
243 /* B. port=0 here means: delete for all ports */
245 stp_trace("%s (all, start stpm)",
249 STP_OUT_flush_lt (0, this->vlan_id
, LT_FLASH_ONLY_THE_PORT
, "start stpm");
252 (void) _stp_stpm_iterate_machines (this, _stp_stpm_init_machine
, False
);
253 (void) STP_stpm_update (this);
260 STP_stpm_stop (STPM_T
* this)
265 STP_stpm_update (STPM_T
* this) /* returns number of loops */
267 register Bool need_state_change
;
268 register int number_of_loops
= 0;
270 need_state_change
= False
;
272 for (;;) {/* loop until not need changes */
273 need_state_change
= _stp_stpm_iterate_machines (this,
276 if (! need_state_change
) break;
279 /* here we know, that at least one stater must be
280 updated (it has changed state) */
281 number_of_loops
+= _stp_stpm_iterate_machines (this,
287 return number_of_loops
;
291 STP_compute_bridge_id (STPM_T
* this)
293 register PORT_T
* port
;
294 register PORT_T
* min_num_port
= NULL
;
297 for (port
= this->ports
; port
; port
= port
->next
) {
298 if (! port_index
|| port
->port_index
< port_index
) {
300 port_index
= port
->port_index
;
304 if (! min_num_port
) return NULL
; /* IMHO, it may not be */
306 STP_OUT_get_port_mac (min_num_port
->port_index
, this->BrId
.addr
);
312 STP_stpm_get_the_list (void)
318 STP_stpm_update_after_bridge_management (STPM_T
* this)
320 register PORT_T
* port
;
322 for (port
= this->ports
; port
; port
= port
->next
) {
323 port
->reselect
= True
;
324 port
->selected
= False
;
329 STP_stpm_check_bridge_priority (STPM_T
* this)
331 register STPM_T
* oth
;
333 for (oth
= bridges
; oth
; oth
= oth
->next
) {
334 if (STP_ENABLED
== oth
->admin_state
&& oth
!= this &&
335 ! STP_VECT_compare_bridge_id (&this->BrId
, &oth
->BrId
)) {
336 return STP_Invalid_Bridge_Priority
;
344 STP_stpm_get_port_name_by_id (STPM_T
* this, PORT_ID port_id
)
346 register PORT_T
* port
;
348 for (port
= this->ports
; port
; port
= port
->next
) {
349 if (port_id
== port
->port_id
) {
350 return port
->port_name
;