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
;
31 /* We can flush learned fdb by port, so set this in stpm.c and topoch.c */
32 /* This doesn't seem to solve the topology change problems. Don't use it yet */
33 //#define STRONGLY_SPEC_802_1W
36 _stp_stpm_init_machine (STATE_MACH_T
* this)
39 (*(this->concreteEnterState
)) (this);
44 _stp_stpm_iterate_machines (STPM_T
* this,
45 int (*iter_callb
) (STATE_MACH_T
*),
46 Bool exit_on_non_zero_ret
)
48 register STATE_MACH_T
* stater
;
49 register PORT_T
* port
;
52 /* state machines per bridge */
53 for (stater
= this->machines
; stater
; stater
= stater
->next
) {
54 iret
= (*iter_callb
) (stater
);
55 if (exit_on_non_zero_ret
&& iret
)
61 /* state machines per port */
62 for (port
= this->ports
; port
; port
= port
->next
) {
63 for (stater
= port
->machines
; stater
; stater
= stater
->next
) {
64 iret
= (*iter_callb
) (stater
);
65 if (exit_on_non_zero_ret
&& iret
)
76 _stp_stpm_init_data (STPM_T
* this)
78 STP_VECT_create (&this->rootPrio
,
84 this->BrTimes
.MessageAge
= 0;
86 STP_copy_times (&this->rootTimes
, &this->BrTimes
);
90 _check_topoch (STPM_T
* this)
92 register PORT_T
* port
;
94 for (port
= this->ports
; port
; port
= port
->next
) {
103 STP_stpm_one_second (STPM_T
* param
)
105 STPM_T
* this = (STPM_T
*) param
;
106 register PORT_T
* port
;
109 if (STP_ENABLED
!= this->admin_state
) return;
111 for (port
= this->ports
; port
; port
= port
->next
) {
112 for (iii
= 0; iii
< TIMERS_NUMBER
; iii
++) {
113 if (*(port
->timers
[iii
]) > 0) {
114 (*port
->timers
[iii
])--;
120 STP_stpm_update (this);
121 this->Topo_Change
= _check_topoch (this);
122 if (this->Topo_Change
) {
123 this->Topo_Change_Count
++;
124 this->timeSince_Topo_Change
= 0;
126 this->Topo_Change_Count
= 0;
127 this->timeSince_Topo_Change
++;
132 STP_stpm_create (int vlan_id
, char* name
)
136 STP_NEW_IN_LIST(this, STPM_T
, bridges
, "stp instance");
138 this->admin_state
= STP_DISABLED
;
140 this->vlan_id
= vlan_id
;
142 STP_STRDUP(this->name
, name
, "stp bridge name");
145 this->machines
= NULL
;
148 STP_STATE_MACH_IN_LIST(rolesel
);
151 /* this->rolesel->debug = 2; */
158 STP_stpm_enable (STPM_T
* this, UID_STP_MODE_T admin_state
)
162 if (admin_state
== this->admin_state
) {
163 /* nothing to do :) */
167 if (STP_ENABLED
== admin_state
) {
168 rc
= STP_stpm_start (this);
169 this->admin_state
= admin_state
;
171 this->admin_state
= admin_state
;
172 STP_stpm_stop (this);
179 STP_stpm_delete (STPM_T
* this)
181 register STPM_T
* tmp
;
182 register STPM_T
* prev
;
183 register STATE_MACH_T
* stater
;
184 register PORT_T
* port
;
187 STP_stpm_enable (this, STP_DISABLED
);
189 for (stater
= this->machines
; stater
; ) {
190 pv
= (void*) stater
->next
;
191 STP_state_mach_delete (stater
);
192 this->machines
= stater
= (STATE_MACH_T
*) pv
;
195 for (port
= this->ports
; port
; ) {
196 pv
= (void*) port
->next
;
197 STP_port_delete (port
);
198 this->ports
= port
= (PORT_T
*) pv
;
202 for (tmp
= bridges
; tmp
; tmp
= tmp
->next
) {
203 if (tmp
->vlan_id
== this->vlan_id
) {
205 prev
->next
= this->next
;
207 bridges
= this->next
;
211 STP_FREE(this->name
, "stp bridge name");
212 STP_FREE(this, "stp instance");
220 STP_stpm_start (STPM_T
* this)
222 register PORT_T
* port
;
225 if (! this->ports
) { /* there are not any ports :( */
226 return STP_There_Are_No_Ports
;
230 if (! STP_compute_bridge_id (this)) {/* can't compute bridge id ? :( */
231 return STP_Cannot_Compute_Bridge_Prio
;
234 /* check, that the stpm has unique bridge Id */
235 if (0 != STP_stpm_check_bridge_priority (this)) {
236 /* there is an enabled bridge with same ID :( */
237 return STP_Invalid_Bridge_Priority
;
240 _stp_stpm_init_data (this);
242 for (port
= this->ports
; port
; port
= port
->next
) {
243 STP_port_init (port
, this, True
);
246 #ifndef STRONGLY_SPEC_802_1W
247 /* A. see comment near STRONGLY_SPEC_802_1W in topoch.c */
248 /* B. port=0 here means: delete for all ports */
250 stp_trace("%s (all, start stpm)",
254 STP_OUT_flush_lt (0, this->vlan_id
, LT_FLASH_ONLY_THE_PORT
, "start stpm");
257 _stp_stpm_iterate_machines (this, _stp_stpm_init_machine
, False
);
258 STP_stpm_update (this);
264 STP_stpm_stop (STPM_T
* this)
269 STP_stpm_update (STPM_T
* this) /* returns number of loops */
271 register Bool need_state_change
;
272 register int number_of_loops
= 0;
274 need_state_change
= False
;
276 for (;;) {/* loop until not need changes */
277 need_state_change
= _stp_stpm_iterate_machines (this,
280 if (! need_state_change
) return number_of_loops
;
283 /* here we know, that at least one stater must be
284 updated (it has changed state) */
285 number_of_loops
+= _stp_stpm_iterate_machines (this,
291 return number_of_loops
;
295 STP_compute_bridge_id (STPM_T
* this)
297 register PORT_T
* port
;
298 unsigned char old
[6], new[6];
299 memset(&old
, 0xff, sizeof(old
));
301 for (port
= this->ports
; port
; port
= port
->next
) {
302 STP_OUT_get_port_mac (port
->port_index
, new);
303 if (memcmp(new, old
, sizeof(old
)) < 0)
304 memcpy(old
, new, sizeof(old
));
307 memcpy(this->BrId
.addr
, old
, sizeof(old
));
313 STP_stpm_get_the_list (void)
319 STP_stpm_update_after_bridge_management (STPM_T
* this)
321 register PORT_T
* port
;
323 for (port
= this->ports
; port
; port
= port
->next
) {
324 port
->reselect
= True
;
325 port
->selected
= False
;
330 STP_stpm_check_bridge_priority (STPM_T
* this)
332 register STPM_T
* oth
;
334 for (oth
= bridges
; oth
; oth
= oth
->next
) {
335 if (STP_ENABLED
== oth
->admin_state
&& oth
!= this &&
336 ! STP_VECT_compare_bridge_id (&this->BrId
, &oth
->BrId
)) {
337 return STP_Invalid_Bridge_Priority
;
345 STP_stpm_get_port_name_by_id (STPM_T
* this, PORT_ID port_id
)
347 register PORT_T
* port
;
349 for (port
= this->ports
; port
; port
= port
->next
) {
350 if (port_id
== port
->port_id
) {
351 return port
->port_name
;