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 **********************************************************************/
25 #include "stp_vectors.h"
27 /* The Port Information State Machine : 17.21 */
41 #define GET_STATE_NAME STP_info_get_state_name
46 _stp_dump (char* title
, unsigned char* buff
, int len
)
50 stp_trace ("\n%s:", title
);
51 for (iii
= 0; iii
< len
; iii
++) {
52 if (! (iii
% 24)) stp_trace ("\n%6d:", iii
);
53 if (! (iii
% 8)) stp_trace (" ");
54 stp_trace ("%02lx", (unsigned long) buff
[iii
]);
61 rcvBpdu (STATE_MACH_T
* this)
64 register PORT_T
* port
= this->owner
.port
;
66 if (port
->msgBpduType
== BPDU_TOPO_CHANGE_TYPE
) {
69 stp_trace ("%s", "rcvBpdu: OtherMsg:BPDU_TOPO_CHANGE_TYPE");
75 port
->msgPortRole
= RSTP_PORT_ROLE_UNKN
;
77 if (BPDU_RSTP
== port
->msgBpduType
) {
78 port
->msgPortRole
= (port
->msgFlags
& PORT_ROLE_MASK
) >> PORT_ROLE_OFFS
;
81 if (RSTP_PORT_ROLE_DESGN
== port
->msgPortRole
||
82 BPDU_CONFIG_TYPE
== port
->msgBpduType
) {
83 bridcmp
= STP_VECT_compare_vector (&port
->msgPrio
, &port
->portPrio
);
86 (! STP_VECT_compare_bridge_id (&port
->msgPrio
.design_bridge
,
87 &port
->portPrio
.design_bridge
) &&
88 port
->msgPrio
.design_port
== port
->portPrio
.design_port
&&
89 STP_compare_times (&port
->msgTimes
, &port
->portTimes
))) {
92 stp_trace ("rcvBpdu: SuperiorDesignateMsg:bridcmp=%d", (int) bridcmp
);
95 return SuperiorDesignateMsg
;
99 if (BPDU_CONFIG_TYPE
== port
->msgBpduType
||
100 RSTP_PORT_ROLE_DESGN
== port
->msgPortRole
) {
101 if (! STP_VECT_compare_vector (&port
->msgPrio
,
103 ! STP_compare_times (&port
->msgTimes
, &port
->portTimes
)) {
106 stp_trace ("%s", "rcvBpdu: RepeatedDesignateMsg");
109 return RepeatedDesignateMsg
;
113 if (RSTP_PORT_ROLE_ROOT
== port
->msgBpduType
&&
114 port
->operPointToPointMac
&&
115 ! STP_VECT_compare_bridge_id (&port
->msgPrio
.design_bridge
,
116 &port
->portPrio
.design_bridge
) &&
117 AGREEMENT_BIT
& port
->msgFlags
) {
120 stp_trace ("%s", "rcvBpdu: ConfirmedRootMsg");
123 return ConfirmedRootMsg
;
128 if (RSTP_PORT_ROLE_ROOT
== port
->msgBpduType
) {
129 if (!port
->operPointToPointMac
) {
130 stp_trace("rcvBpdu: OtherMsg: not point-to-point MAC");
131 } else if (STP_VECT_compare_bridge_id (&port
->msgPrio
.design_bridge
,
132 &port
->portPrio
.design_bridge
)) {
133 STP_VECT_br_id_print("rcvBpdu: OtherMsg: msgPrio", &port
->msgPrio
.design_bridge
, True
);
134 STP_VECT_br_id_print("rcvBpdu: portPrio", &port
->portPrio
.design_bridge
, True
);
136 stp_trace("rcvBpdu: OtherMsg: agreement bit not set");
139 stp_trace ("rcvBpdu: OtherMsg: type %d", port
->msgBpduType
);
148 recordProposed (STATE_MACH_T
* this, char* reason
)
150 register PORT_T
* port
= this->owner
.port
;
152 if (RSTP_PORT_ROLE_DESGN
== port
->msgPortRole
&&
153 (PROPOSAL_BIT
& port
->msgFlags
) &&
154 port
->operPointToPointMac
) {
161 setTcFlags (STATE_MACH_T
* this)
163 register PORT_T
* port
= this->owner
.port
;
165 if (BPDU_TOPO_CHANGE_TYPE
== port
->msgBpduType
) {
168 stp_trace ("port %s rx rcvdTcn", port
->port_name
);
171 port
->rcvdTcn
= True
;
173 if (TOPOLOGY_CHANGE_BIT
& port
->msgFlags
) {
176 stp_trace ("(%s-%s) rx rcvdTc 0X%lx",
177 port
->owner
->name
, port
->port_name
,
178 (unsigned long) port
->msgFlags
);
183 if (TOPOLOGY_CHANGE_ACK_BIT
& port
->msgFlags
) {
186 stp_trace ("port %s rx rcvdTcAck 0X%lx",
188 (unsigned long) port
->msgFlags
);
191 port
->rcvdTcAck
= True
;
197 updtBPDUVersion (STATE_MACH_T
* this)
199 register PORT_T
* port
= this->owner
.port
;
201 if (BPDU_TOPO_CHANGE_TYPE
== port
->msgBpduType
) {
202 port
->rcvdSTP
= True
;
205 if (port
->msgBpduVersion
< 2) {
206 port
->rcvdSTP
= True
;
209 if (BPDU_RSTP
== port
->msgBpduType
) {
210 /* port->port->owner->ForceVersion >= NORMAL_RSTP
211 we have checked in STP_info_rx_bpdu */
212 port
->rcvdRSTP
= True
;
217 updtRcvdInfoWhile (STATE_MACH_T
* this)
219 register int eff_age
, dm
, dt
;
221 register PORT_T
* port
= this->owner
.port
;
223 eff_age
= ( + port
->portTimes
.MaxAge
) / 16;
224 if (eff_age
< 1) eff_age
= 1;
225 eff_age
+= port
->portTimes
.MessageAge
;
227 if (eff_age
<= port
->portTimes
.MaxAge
) {
228 hello3
= 3 * port
->portTimes
.HelloTime
;
229 dm
= port
->portTimes
.MaxAge
- eff_age
;
234 port
->rcvdInfoWhile
= dt
;
236 stp_trace ("ma=%d eff_age=%d dm=%d dt=%d p=%s",
237 (int) port->portTimes.MessageAge,
238 (int) eff_age, (int) dm, (int) dt, port->port_name);
241 port
->rcvdInfoWhile
= 0;
244 /*if (this->debug) */
246 stp_trace ("port %s: MaxAge=%d MessageAge=%d HelloTime=%d rcvdInfoWhile=null !",
248 (int) port
->portTimes
.MaxAge
,
249 (int) port
->portTimes
.MessageAge
,
250 (int) port
->portTimes
.HelloTime
);
260 STP_info_rx_bpdu (PORT_T
* port
, struct stp_bpdu_t
* bpdu
, size_t len
)
263 _stp_dump ("\nall BPDU", ((unsigned char*) bpdu
) - 12, len
+ 12);
264 _stp_dump ("ETH_HEADER", (unsigned char*) &bpdu
->eth
, 5);
265 _stp_dump ("BPDU_HEADER", (unsigned char*) &bpdu
->hdr
, 4);
266 stp_trace ("protocol=%02x%02x version=%02x bpdu_type=%02x\n",
267 bpdu
->hdr
.protocol
[0], bpdu
->hdr
.protocol
[1],
268 bpdu
->hdr
.version
, bpdu
->hdr
.bpdu_type
);
270 _stp_dump ("\nBPDU_BODY", (unsigned char*) &bpdu
->body
, sizeof (BPDU_BODY_T
) + 2);
271 stp_trace ("flags=%02x\n", bpdu
->body
.flags
);
272 _stp_dump ("root_id", bpdu
->body
.root_id
, 8);
273 _stp_dump ("root_path_cost", bpdu
->body
.root_path_cost
, 4);
274 _stp_dump ("bridge_id", bpdu
->body
.bridge_id
, 8);
275 _stp_dump ("port_id", bpdu
->body
.port_id
, 2);
276 _stp_dump ("message_age", bpdu
->body
.message_age
, 2);
277 _stp_dump ("max_age", bpdu
->body
.max_age
, 2);
278 _stp_dump ("hello_time", bpdu
->body
.hello_time
, 2);
279 _stp_dump ("forward_delay", bpdu
->body
.forward_delay
, 2);
280 _stp_dump ("ver_1_len", bpdu
->ver_1_len
, 2);
283 /* check bpdu type */
284 switch (bpdu
->hdr
.bpdu_type
) {
285 case BPDU_CONFIG_TYPE
:
286 port
->rx_cfg_bpdu_cnt
++;
288 if (port
->info
->debug
)
289 stp_trace ("CfgBpdu on port %s", port
->port_name
);
291 if (port
->admin_non_stp
) return;
292 port
->rcvdBpdu
= True
;
294 case BPDU_TOPO_CHANGE_TYPE
:
295 port
->rx_tcn_bpdu_cnt
++;
297 if (port
->info
->debug
)
298 stp_trace ("TcnBpdu on port %s", port
->port_name
);
300 if (port
->admin_non_stp
) return;
301 port
->rcvdBpdu
= True
;
302 port
->msgBpduVersion
= bpdu
->hdr
.version
;
303 port
->msgBpduType
= bpdu
->hdr
.bpdu_type
;
306 stp_trace ("RX undef bpdu type=%d", (int) bpdu
->hdr
.bpdu_type
);
309 port
->rx_rstp_bpdu_cnt
++;
310 if (port
->admin_non_stp
) return;
311 if (port
->owner
->ForceVersion
>= NORMAL_RSTP
) {
312 port
->rcvdBpdu
= True
;
317 if (port
->info
->debug
)
318 stp_trace ("BPDU_RSTP on port %s", port
->port_name
);
323 port
->msgBpduVersion
= bpdu
->hdr
.version
;
324 port
->msgBpduType
= bpdu
->hdr
.bpdu_type
;
325 port
->msgFlags
= bpdu
->body
.flags
;
328 STP_VECT_get_vector (&bpdu
->body
, &port
->msgPrio
);
329 port
->msgPrio
.bridge_port
= port
->port_id
;
332 STP_get_times (&bpdu
->body
, &port
->msgTimes
);
334 /* 17.18.25, 17.18.26 : see setTcFlags() */
337 void STP_info_enter_state (STATE_MACH_T
* this)
339 register PORT_T
* port
= this->owner
.port
;
341 switch (this->State
) {
343 port
->rcvdMsg
= OtherMsg
;
344 port
->msgBpduType
= (unsigned char)-1;
345 port
->msgPortRole
= RSTP_PORT_ROLE_UNKN
;
348 /* clear port statistics */
349 port
->rx_cfg_bpdu_cnt
=
350 port
->rx_rstp_bpdu_cnt
=
351 port
->rx_tcn_bpdu_cnt
= 0;
354 port
->rcvdBpdu
= port
->rcvdRSTP
= port
->rcvdSTP
= False
;
355 port
->updtInfo
= port
->proposing
= False
; /* In DISABLED */
356 port
->agreed
= port
->proposed
= False
;
357 port
->rcvdInfoWhile
= 0;
358 port
->infoIs
= Disabled
;
359 port
->reselect
= True
;
360 port
->selected
= False
;
362 case ENABLED
: /* IEEE 802.1y, 17.21, Z.14 */
363 STP_VECT_copy (&port
->portPrio
, &port
->designPrio
);
364 STP_copy_times (&port
->portTimes
, &port
->designTimes
);
368 port
->reselect
= True
;
369 port
->selected
= False
;
372 STP_VECT_copy (&port
->portPrio
, &port
->designPrio
);
373 STP_copy_times (&port
->portTimes
, &port
->designTimes
);
374 port
->updtInfo
= False
;
375 port
->agreed
= port
->synced
= False
; /* In UPDATE */
376 port
->proposed
= port
->proposing
= False
; /* in UPDATE */
378 port
->newInfo
= True
;
381 STP_VECT_br_id_print ("updated: portPrio.design_bridge",
382 &port
->portPrio
.design_bridge
, True
);
383 STP_VECT_br_id_print ("updated: portPrio.root_bridge",
384 &port
->portPrio
.root_bridge
, True
);
391 port
->rcvdMsg
= rcvBpdu (this);
392 updtBPDUVersion (this);
394 port
->rcvdBpdu
= False
;
397 STP_VECT_copy (&port
->portPrio
, &port
->msgPrio
);
398 STP_copy_times (&port
->portTimes
, &port
->msgTimes
);
399 updtRcvdInfoWhile (this);
400 #if 1 /* due 802.1y, Z.7 */
401 port
->agreed
= False
; /* deleted due 802.y in SUPERIOR */
402 port
->synced
= False
; /* due 802.y deleted in SUPERIOR */
404 port
->proposing
= False
; /* in SUPERIOR */
405 port
->proposed
= recordProposed (this, "SUPERIOR");
406 port
->infoIs
= Received
;
407 port
->reselect
= True
;
408 port
->selected
= False
;
411 STP_VECT_br_id_print ("stored: portPrio.design_bridge",
412 &port
->portPrio
.design_bridge
, True
);
413 STP_VECT_br_id_print ("stored: portPrio.root_bridge",
414 &port
->portPrio
.root_bridge
, True
);
415 stp_trace ("proposed=%d on port %s",
416 (int) port
->proposed
, port
->port_name
);
421 port
->proposed
= recordProposed (this, "REPEAT");
422 updtRcvdInfoWhile (this);
426 if (port
->roletrns
->debug
) {
427 stp_trace ("(%s-%s) rx AGREEMENT flag !",
428 port
->owner
->name
, port
->port_name
);
433 port
->proposing
= False
; /* In AGREEMENT */
439 Bool
STP_info_check_conditions (STATE_MACH_T
* this)
441 register PORT_T
* port
= this->owner
.port
;
443 if ((! port
->portEnabled
&& port
->infoIs
!= Disabled
) || BEGIN
== this->State
) {
444 return STP_hop_2_state (this, DISABLED
);
447 switch (this->State
) {
449 if (port
->updtInfo
) {
450 return STP_hop_2_state (this, DISABLED
);
452 if (port
->portEnabled
&& port
->selected
) {
453 return STP_hop_2_state (this, ENABLED
);
455 if (port
->rcvdBpdu
) {
456 return STP_hop_2_state (this, DISABLED
);
459 case ENABLED
: /* IEEE 802.1y, 17.21, Z.14 */
460 return STP_hop_2_state (this, AGED
);
462 if (port
->selected
&& port
->updtInfo
) {
463 return STP_hop_2_state (this, UPDATE
);
467 return STP_hop_2_state (this, CURRENT
);
469 if (port
->selected
&& port
->updtInfo
) {
470 return STP_hop_2_state (this, UPDATE
);
473 if (Received
== port
->infoIs
&&
474 ! port
->rcvdInfoWhile
&&
477 return STP_hop_2_state (this, AGED
);
479 if (port
->rcvdBpdu
&& !port
->updtInfo
) {
480 return STP_hop_2_state (this, RECEIVE
);
484 switch (port
->rcvdMsg
) {
485 case SuperiorDesignateMsg
:
486 return STP_hop_2_state (this, SUPERIOR
);
487 case RepeatedDesignateMsg
:
488 return STP_hop_2_state (this, REPEAT
);
489 case ConfirmedRootMsg
:
490 return STP_hop_2_state (this, AGREEMENT
);
492 return STP_hop_2_state (this, CURRENT
);
495 return STP_hop_2_state (this, CURRENT
);
497 return STP_hop_2_state (this, CURRENT
);
499 return STP_hop_2_state (this, CURRENT
);