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
11 *
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.
16 *
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 **********************************************************************/
22
23 /* STP machine instance : bridge per VLAN: 17.17 */
24
25 #include "base.h"
26 #include "stpm.h"
27 #include "stp_to.h" /* for STP_OUT_flush_lt */
28
29 static STPM_T *bridges = NULL;
30
31 static int
_stp_stpm_init_machine(STATE_MACH_T * this)32 _stp_stpm_init_machine (STATE_MACH_T* this)
33 {
34 this->State = BEGIN;
35 (*(this->concreteEnterState)) (this);
36 return 0;
37 }
38
39 static int
_stp_stpm_iterate_machines(STPM_T * this,int (* iter_callb)(STATE_MACH_T *),Bool exit_on_non_zero_ret)40 _stp_stpm_iterate_machines (STPM_T* this,
41 int (*iter_callb) (STATE_MACH_T*),
42 Bool exit_on_non_zero_ret)
43 {
44 register STATE_MACH_T* stater;
45 register PORT_T* port;
46 int iret, mret = 0;
47
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)
52 return iret;
53 else
54 mret += iret;
55 }
56
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)
62 return iret;
63 else
64 mret += iret;
65 }
66 }
67
68 return mret;
69 }
70
71 void
_stp_stpm_init_data(STPM_T * this)72 _stp_stpm_init_data (STPM_T* this)
73 {
74 STP_VECT_create (&this->rootPrio,
75 &this->BrId,
76 0,
77 &this->BrId,
78 0, 0);
79
80 this->BrTimes.MessageAge = 0;
81
82 STP_copy_times (&this->rootTimes, &this->BrTimes);
83 }
84
85 static unsigned char
_check_topoch(STPM_T * this)86 _check_topoch (STPM_T* this)
87 {
88 register PORT_T* port;
89
90 for (port = this->ports; port; port = port->next) {
91 if (port->tcWhile) {
92 return 1;
93 }
94 }
95 return 0;
96 }
97
98 void
STP_stpm_one_second(STPM_T * param)99 STP_stpm_one_second (STPM_T* param)
100 {
101 STPM_T* this = (STPM_T*) param;
102 register PORT_T* port;
103 register int iii;
104
105 if (STP_ENABLED != this->admin_state) return;
106
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])--;
111 }
112 }
113 port->uptime++;
114 }
115
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;
121 } else {
122 this->Topo_Change_Count = 0;
123 this->timeSince_Topo_Change++;
124 }
125 }
126
127 STPM_T*
STP_stpm_create(int vlan_id,char * name)128 STP_stpm_create (int vlan_id, char* name)
129 {
130 STPM_T* this;
131
132 STP_NEW_IN_LIST(this, STPM_T, bridges, "stp instance");
133
134 this->admin_state = STP_DISABLED;
135
136 this->vlan_id = vlan_id;
137 if (name) {
138 STP_STRDUP(this->name, name, "stp bridge name");
139 }
140
141 this->machines = NULL;
142 this->ports = NULL;
143
144 STP_STATE_MACH_IN_LIST(rolesel);
145
146 #ifdef STP_DBG
147 /* this->rolesel->debug = 2; */
148 #endif
149
150 return this;
151 }
152
153 int
STP_stpm_enable(STPM_T * this,UID_STP_MODE_T admin_state)154 STP_stpm_enable (STPM_T* this, UID_STP_MODE_T admin_state)
155 {
156 int rc = 0;
157
158 if (admin_state == this->admin_state) {
159 /* nothing to do :) */
160 return 0;
161 }
162
163 if (STP_ENABLED == admin_state) {
164 if (this->ports)
165 rc = STP_stpm_start (this);
166 this->admin_state = admin_state;
167 } else {
168 this->admin_state = admin_state;
169 STP_stpm_stop (this);
170 }
171
172 return rc;
173 }
174
175 void
STP_stpm_delete(STPM_T * this)176 STP_stpm_delete (STPM_T* this)
177 {
178 register STPM_T* tmp;
179 register STPM_T* prev;
180 register STATE_MACH_T* stater;
181 register PORT_T* port;
182 register void* pv;
183
184 (void) STP_stpm_enable (this, STP_DISABLED);
185
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;
190 }
191
192 for (port = this->ports; port; ) {
193 pv = (void*) port->next;
194 STP_port_delete (port);
195 this->ports = port = (PORT_T*) pv;
196 }
197
198 prev = NULL;
199 for (tmp = bridges; tmp; tmp = tmp->next) {
200 if (tmp->vlan_id == this->vlan_id) {
201 if (prev) {
202 prev->next = this->next;
203 } else {
204 bridges = this->next;
205 }
206
207 if (this->name)
208 STP_FREE(this->name, "stp bridge name");
209 STP_FREE(this, "stp instance");
210 break;
211 }
212 prev = tmp;
213 }
214 }
215
216 int
STP_stpm_start(STPM_T * this)217 STP_stpm_start (STPM_T* this)
218 {
219 register PORT_T* port;
220
221 if (! this->ports) { /* there are not any ports :( */
222 return STP_There_Are_No_Ports;
223 }
224
225 if (! STP_compute_bridge_id (this)) {/* can't compute bridge id ? :( */
226 return STP_Cannot_Compute_Bridge_Prio;
227 }
228
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;
233 }
234
235 _stp_stpm_init_data (this);
236
237 for (port = this->ports; port; port = port->next) {
238 STP_port_init (port, this, True);
239 }
240
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 */
244 #ifdef STP_DBG
245 stp_trace("%s (all, start stpm)",
246 "clearFDB");
247 #endif
248
249 STP_OUT_flush_lt (0, this->vlan_id, LT_FLASH_ONLY_THE_PORT, "start stpm");
250 #endif
251
252 (void) _stp_stpm_iterate_machines (this, _stp_stpm_init_machine, False);
253 (void) STP_stpm_update (this);
254
255 return 0;
256 }
257
258 /* ARGSUSED */
259 void
STP_stpm_stop(STPM_T * this)260 STP_stpm_stop (STPM_T* this)
261 {
262 }
263
264 int
STP_stpm_update(STPM_T * this)265 STP_stpm_update (STPM_T* this) /* returns number of loops */
266 {
267 register Bool need_state_change;
268 register int number_of_loops = 0;
269
270 need_state_change = False;
271
272 for (;;) {/* loop until not need changes */
273 need_state_change = _stp_stpm_iterate_machines (this,
274 STP_check_condition,
275 True);
276 if (! need_state_change) break;
277
278 number_of_loops++;
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,
282 STP_change_state,
283 False);
284
285 }
286
287 return number_of_loops;
288 }
289
290 BRIDGE_ID *
STP_compute_bridge_id(STPM_T * this)291 STP_compute_bridge_id (STPM_T* this)
292 {
293 register PORT_T* port;
294 register PORT_T* min_num_port = NULL;
295 int port_index = 0;
296
297 for (port = this->ports; port; port = port->next) {
298 if (! port_index || port->port_index < port_index) {
299 min_num_port = port;
300 port_index = port->port_index;
301 }
302 }
303
304 if (! min_num_port) return NULL; /* IMHO, it may not be */
305
306 STP_OUT_get_port_mac (min_num_port->port_index, this->BrId.addr);
307
308 return &this->BrId;
309 }
310
311 STPM_T*
STP_stpm_get_the_list(void)312 STP_stpm_get_the_list (void)
313 {
314 return bridges;
315 }
316
317 void
STP_stpm_update_after_bridge_management(STPM_T * this)318 STP_stpm_update_after_bridge_management (STPM_T* this)
319 {
320 register PORT_T* port;
321
322 for (port = this->ports; port; port = port->next) {
323 port->reselect = True;
324 port->selected = False;
325 }
326 }
327
328 int
STP_stpm_check_bridge_priority(STPM_T * this)329 STP_stpm_check_bridge_priority (STPM_T* this)
330 {
331 register STPM_T* oth;
332
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;
337 }
338 }
339
340 return 0;
341 }
342
343 const char*
STP_stpm_get_port_name_by_id(STPM_T * this,PORT_ID port_id)344 STP_stpm_get_port_name_by_id (STPM_T* this, PORT_ID port_id)
345 {
346 register PORT_T* port;
347
348 for (port = this->ports; port; port = port->next) {
349 if (port_id == port->port_id) {
350 return port->port_name;
351 }
352 }
353
354 return "Undef?";
355 }
356
357
358
359
360
361