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 **********************************************************************/
27 /* The Port Information State Machine : 17.21 */
28 /*kd: unter hinzufĆ¼gte man die neu Namen, die im 802.1D definieren*/
37 CHOOSE(SUPERIOR_DESIGNATED), \
38 CHOOSE(REPEATED_DESIGNATED), \
39 CHOOSE(INFERIOR_DESIGNATED), \
40 CHOOSE(NOT_DESIGNATED), \
44 #define GET_STATE_NAME STP_info_get_state_name
47 /******************************************************************/
48 void _stp_dump (char* title
, unsigned char* buff
, int len
)
52 printf ("\n%s:", title
);
53 for (iii
= 0; iii
< len
; iii
++) {
54 if (! (iii
% 24)) Print ("\n%6d:", iii
);
55 if (! (iii
% 8)) Print (" ");
56 Print ("%02lx", (unsigned long) buff
[iii
]);
61 /* 17.21.8 checked leu */
62 static RCVD_MSG_T
rcvInfo (STATE_MACH_T
* this)
65 register PORT_T
* port
= this->owner
.port
;
67 if (port
->msgBpduType
== BPDU_TOPO_CHANGE_TYPE
) {
70 stp_trace ("%s", "OtherInfo:BPDU_TOPO_CHANGE_TYPE");
76 port
->msgPortRole
= RSTP_PORT_ROLE_UNKN
;
78 if (BPDU_RSTP
== port
->msgBpduType
) {
79 port
->msgPortRole
= (port
->msgFlags
& PORT_ROLE_MASK
) >> PORT_ROLE_OFFS
;
83 * msgPrio superior to portPrio: < 0 OR
84 * msgPrio same as portPrio: == 0
85 * Note leu: We compare only the following compontents here:
86 * vec = (R:RPC:D:PD:PB)
87 * frist clause: superior
88 * msgPrio = (R:RPC:D:PD:-)
89 * portPrio = (R:RPC:D:PD:-)
90 * second clause: same as - why exclude R, RPC and PB ???
91 * msgPrio = (-:-:D:PD:-)
92 * portPrio = (-:-:D:PD:-)
95 if (RSTP_PORT_ROLE_DESGN
== port
->msgPortRole
||
96 BPDU_CONFIG_TYPE
== port
->msgBpduType
) {
97 bridcmp
= STP_VECT_compare_vector(&port
->msgPrio
, &port
->portPrio
);
98 /* Clause a) superior info ? */
100 ((STP_VECT_compare_bridge_id(&port
->msgPrio
.design_bridge
,
101 &port
->portPrio
.design_bridge
) == 0) &&
102 (port
->msgPrio
.design_port
== port
->portPrio
.design_port
))) ||
103 /* Clause b) times changed */
105 (STP_compare_times(&port
->msgTimes
, &port
->portTimes
) != 0))) {
108 stp_trace ("SuperiorDesignatednfo: bridcmp=%d", (int) bridcmp
);
111 return SuperiorDesignatedInfo
;
116 * msgPrio same as portPrio: == 0
117 * msgTimes same as portTimes: == 0
119 if (BPDU_CONFIG_TYPE
== port
->msgBpduType
||
120 RSTP_PORT_ROLE_DESGN
== port
->msgPortRole
) {
121 if ((STP_VECT_compare_vector(&port
->msgPrio
, &port
->portPrio
) == 0) &&
122 (STP_compare_times(&port
->msgTimes
, &port
->portTimes
) == 0)) {
125 stp_trace ("%s", "RepeatedDesignatedInfo");
128 return RepeatedDesignatedInfo
;
133 * msgPrio worse than portPrio: > 0
135 if (RSTP_PORT_ROLE_DESGN
== port
->msgPortRole
||
136 BPDU_CONFIG_TYPE
== port
->msgBpduType
) {
137 bridcmp
= STP_VECT_compare_vector(&port
->msgPrio
, &port
->portPrio
);
141 stp_trace ("%s %d", "InferiorDesignatedInfo", (int) bridcmp
);
144 return InferiorDesignatedInfo
;
149 * msgPrio same as or worse than portPrio: >= 0
152 if (RSTP_PORT_ROLE_ROOT
== port
->msgPortRole
||
153 RSTP_PORT_ROLE_ALTBACK
== port
->msgPortRole
||
154 BPDU_CONFIG_TYPE
== port
->msgBpduType
) {
155 bridcmp
= STP_VECT_compare_vector (&port
->msgPrio
, &port
->portPrio
);
157 if ((bridcmp
>= 0) &&
158 (STP_compare_times (&port
->msgTimes
, &port
->portTimes
) == 0)) {
164 stp_trace ("%s", "InferiorRootAlternateInfo");
167 return InferiorRootAlternateInfo
;
172 stp_trace ("%s", "OtherInfo");
175 return OtherInfo
; /* kd: die neue Name*/
179 /******************************************************************/
180 /* 17.21.11 checked leu */
181 static Bool
recordProposal (STATE_MACH_T
* this)
183 register PORT_T
* port
= this->owner
.port
;
185 if (RSTP_PORT_ROLE_DESGN
== port
->msgPortRole
&&
186 (PROPOSAL_BIT
& port
->msgFlags
)) {
187 port
->proposed
= True
;
193 /******************************************************************/
194 /* 17.21.1 checked leu */
195 static Bool
betterorsameInfo (STATE_MACH_T
* this, INFO_IS_T newInfoIs
)
197 register PORT_T
* port
= this->owner
.port
;
198 int bridcmp_a
, bridcmp_b
;
199 bridcmp_a
= STP_VECT_compare_vector(&port
->msgPrio
, &port
->portPrio
);
200 bridcmp_b
= STP_VECT_compare_vector(&port
->designPrio
, &port
->portPrio
);
201 if (((newInfoIs
== Received
&& port
->infoIs
== Received
) &&
203 ((newInfoIs
== Mine
&& port
->infoIs
== Mine
) &&
206 if (port
->info
->debug
){
207 stp_trace("port %s has better or same info: %s True agree=%d cmp(msg,port)=%d cmp(des,port)=%d",
208 port
->port_name
, newInfoIs
== Mine
? "Mine" : "Received",
209 port
->agree
, bridcmp_a
, bridcmp_b
);
215 if (port
->info
->debug
){
216 stp_trace("port %s has worse info: %s False agree=%d cmp(msg,port)=%d cmp(des,port)=%d",
217 port
->port_name
, newInfoIs
== Mine
? "Mine" : "Received",
218 port
->agree
, bridcmp_a
, bridcmp_b
);
225 /****************************************************************/
226 /* 17.21.12 checked leu */
227 static Bool
recordPriority (STATE_MACH_T
* this)
229 register PORT_T
* port
= this->owner
.port
;
231 STP_VECT_copy (&port
->portPrio
, &port
->msgPrio
);
235 /*******************************************************************/
236 /* 17.21.10 checked leu */
237 static Bool
recordDispute (STATE_MACH_T
* this)
239 register PORT_T
* port
= this->owner
.port
;
240 register Bool rd
= False
;
241 if ((BPDU_RSTP
== port
->msgBpduType
) && (port
->msgFlags
& LEARN_BIT
)){
242 rd
= port
->agreed
= True
;
243 port
->proposing
= False
;
244 port
->disputed
= True
;
247 stp_trace ("port %s sets agreed and resets proposing", port
->port_name
);
254 /****************************************************************/
255 /* 17.21.13 checked: leu */
256 static unsigned short recordTimes (STATE_MACH_T
* this)
258 register PORT_T
* port
= this->owner
.port
;
260 port
->portTimes
.MessageAge
= port
->msgTimes
.MessageAge
;
261 port
->portTimes
.MaxAge
= port
->msgTimes
.MaxAge
;
262 port
->portTimes
.ForwardDelay
= port
->msgTimes
.ForwardDelay
;
263 if (port
->msgTimes
.HelloTime
> 1)
264 port
->portTimes
.HelloTime
= port
->msgTimes
.HelloTime
;
266 port
->portTimes
.HelloTime
= 1;
271 /****************************************************************/
272 /* 17.21.17 checked: leu */
273 static Bool
setTcFlags (STATE_MACH_T
* this)
275 register PORT_T
* port
= this->owner
.port
;
277 if (BPDU_TOPO_CHANGE_TYPE
== port
->msgBpduType
) {
280 stp_trace ("port %s rx rcvdTcn", port
->port_name
);
283 port
->rcvdTcn
= True
;
285 if (TOLPLOGY_CHANGE_BIT
& port
->msgFlags
) {
288 stp_trace ("(%s-%s) rx rcvdTc 0X%lx",
289 port
->owner
->name
, port
->port_name
,
290 (unsigned long) port
->msgFlags
);
295 if (TOLPLOGY_CHANGE_ACK_BIT
& port
->msgFlags
) {
298 stp_trace ("port %s rx rcvdTcAck 0X%lx",
300 (unsigned long) port
->msgFlags
);
303 port
->rcvdTcAck
= True
;
309 /*****************************************************************/
310 /* 17.29.11 checked leu */
311 static Bool
rstpVer (STATE_MACH_T
* this)
313 STPM_T
*stpm
= this->owner
.stpm
;
315 if (stpm
->ForceVersion
>= 2)
323 /*****************************************************************/
324 /* 17.21.9 checked leu */
325 static Bool
recordAgreement(STATE_MACH_T
* this)
327 register PORT_T
* port
= this->owner
.port
;
329 if (rstpVer(this) == True
&& port
->operPointToPointMac
== True
330 && (AGREEMENT_BIT
& port
->msgFlags
)) {
331 ra
= port
->agreed
= True
;
332 ra
= port
->proposing
= False
;
335 ra
= port
->agreed
= False
;
339 /****************************************************************/
340 /* 17.21.23: checked leu */
341 static Bool
updtRcvdInfoWhile (STATE_MACH_T
* this)
343 register int eff_age
;
344 register PORT_T
* port
= this->owner
.port
;
346 eff_age
= port
->portTimes
.MessageAge
+ 1;
348 if (eff_age
<= port
->portTimes
.MaxAge
) {
349 port
->rcvdInfoWhile
= 3 * port
->portTimes
.HelloTime
;
352 stp_trace ("port %s: MessageAge=%d EffectiveAge=%d",
354 (int) port
->portTimes
.MessageAge
,
359 port
->rcvdInfoWhile
= 0;
361 stp_trace ("port %s: MaxAge=%d MessageAge=%d HelloTime=%d rcvdInfoWhile=null !",
363 (int) port
->portTimes
.MaxAge
,
364 (int) port
->portTimes
.MessageAge
,
365 (int) port
->portTimes
.HelloTime
);
371 /****************************************************************/
372 void STP_info_rx_bpdu (PORT_T
* port
, struct stp_bpdu_t
* bpdu
, size_t len
)
375 _stp_dump ("\nall BPDU", ((unsigned char*) bpdu
) - 12, len
+ 12);
376 _stp_dump ("ETH_HEADER", (unsigned char*) &bpdu
->eth
, 5);
377 _stp_dump ("BPDU_HEADER", (unsigned char*) &bpdu
->hdr
, 4);
378 printf ("protocol=%02x%02x version=%02x bpdu_type=%02x\n",
379 bpdu
->hdr
.protocol
[0], bpdu
->hdr
.protocol
[1],
380 bpdu
->hdr
.version
, bpdu
->hdr
.bpdu_type
);
382 _stp_dump ("\nBPDU_BODY", (unsigned char*) &bpdu
->body
, sizeof (BPDU_BODY_T
) + 2);
383 printf ("flags=%02x\n", bpdu
->body
.flags
);
384 _stp_dump ("root_id", bpdu
->body
.root_id
, 8);
385 _stp_dump ("root_path_cost", bpdu
->body
.root_path_cost
, 4);
386 _stp_dump ("bridge_id", bpdu
->body
.bridge_id
, 8);
387 _stp_dump ("port_id", bpdu
->body
.port_id
, 2);
388 _stp_dump ("message_age", bpdu
->body
.message_age
, 2);
389 _stp_dump ("max_age", bpdu
->body
.max_age
, 2);
390 _stp_dump ("hello_time", bpdu
->body
.hello_time
, 2);
391 _stp_dump ("forward_delay", bpdu
->body
.forward_delay
, 2);
392 _stp_dump ("ver_1_len", bpdu
->ver_1_len
, 2);
395 /* check bpdu type */
396 switch (bpdu
->hdr
.bpdu_type
) {
398 case BPDU_CONFIG_TYPE
:
399 port
->rx_cfg_bpdu_cnt
++;
401 if (port
->info
->debug
)
402 stp_trace ("CfgBpdu on port %s", port
->port_name
);
404 if (port
->admin_non_stp
) return;
405 port
->rcvdBpdu
= True
;
408 case BPDU_TOPO_CHANGE_TYPE
:
409 port
->rx_tcn_bpdu_cnt
++;
411 if (port
->info
->debug
)
412 stp_trace ("TcnBpdu on port %s", port
->port_name
);
414 if (port
->admin_non_stp
) return;
415 port
->rcvdBpdu
= True
;
416 port
->msgBpduVersion
= bpdu
->hdr
.version
;
417 port
->msgBpduType
= bpdu
->hdr
.bpdu_type
;
421 port
->rx_rstp_bpdu_cnt
++;
422 if (port
->admin_non_stp
) return;
423 if (port
->owner
->ForceVersion
>= NORMAL_RSTP
) {
424 port
->rcvdBpdu
= True
;
429 if (port
->info
->debug
)
430 stp_trace ("BPDU_RSTP on port %s", port
->port_name
);
435 stp_trace ("RX undef bpdu type=%d", (int) bpdu
->hdr
.bpdu_type
);
440 port
->msgBpduVersion
= bpdu
->hdr
.version
;
441 port
->msgBpduType
= bpdu
->hdr
.bpdu_type
;
442 port
->msgFlags
= bpdu
->body
.flags
;
444 STP_VECT_get_vector (&bpdu
->body
, &port
->msgPrio
);
445 port
->msgPrio
.bridge_port
= port
->port_id
;
447 STP_get_times (&bpdu
->body
, &port
->msgTimes
);
450 /****************************************************************/
451 void STP_info_enter_state (STATE_MACH_T
* this)
453 register PORT_T
* port
= this->owner
.port
;
455 switch (this->State
) {
457 port
->rcvdMsg
= OtherInfo
;
458 port
->msgBpduType
= 0xff;
459 port
->msgPortRole
= RSTP_PORT_ROLE_UNKN
;
462 /* clear port statistics */
463 port
->rx_cfg_bpdu_cnt
=
464 port
->rx_rstp_bpdu_cnt
=
465 port
->rx_tcn_bpdu_cnt
= 0;
468 port
->rcvdMsg
= False
;
469 port
->agreed
= port
->proposing
=
470 port
->proposed
= port
->agree
= False
;
471 port
->rcvdInfoWhile
= 0;
472 port
->infoIs
= Disabled
;
473 port
->reselect
= True
;
474 port
->selected
= False
;
477 case ENABLED
: /* IEEE 802.1y, 17.21, Z.14 */
478 STP_VECT_copy (&port
->portPrio
, &port
->designPrio
);
479 STP_copy_times (&port
->portTimes
, &port
->designTimes
);
484 port
->reselect
= True
;
485 port
->selected
= False
;
489 port
->proposed
= port
->proposing
= False
;
490 port
->agreed
= port
->agreed
&& betterorsameInfo (this, Mine
);
491 port
->synced
= port
->synced
&& port
->agreed
;
492 STP_VECT_copy (&port
->portPrio
, &port
->designPrio
);
493 STP_copy_times (&port
->portTimes
, &port
->designTimes
);
494 port
->updtInfo
= False
;
496 port
->newInfo
= True
;
499 STP_VECT_br_id_print ("updated: portPrio.design_bridge",
500 &port
->portPrio
.design_bridge
, True
);
509 port
->rcvdInfo
= rcvInfo (this);
513 case SUPERIOR_DESIGNATED
:
514 port
->agreed
= False
;
515 port
->proposing
= False
;
516 recordProposal (this);
518 port
->agree
= port
->agree
&& betterorsameInfo (this, Received
);
519 recordPriority (this);
521 updtRcvdInfoWhile (this);
522 port
->infoIs
= Received
;
523 port
->reselect
= True
;
524 port
->selected
= False
;
525 port
-> rcvdMsg
= False
;
528 STP_VECT_br_id_print ("stored: portPrio.design_bridge",
529 &port
->portPrio
.design_bridge
, True
);
530 stp_trace ("proposed=%d on port %s",
531 (int) port
->proposed
, port
->port_name
);
536 case REPEATED_DESIGNATED
:
537 recordProposal (this);
539 updtRcvdInfoWhile (this);
540 port
->rcvdMsg
= False
;
543 case INFERIOR_DESIGNATED
:
544 recordDispute (this);
545 port
->rcvdMsg
= False
;
549 recordAgreement (this);
551 port
->rcvdMsg
= False
;
555 port
->rcvdMsg
= False
;
560 /****************************************************************/
561 Bool
STP_info_check_conditions (STATE_MACH_T
* this)
563 register PORT_T
* port
= this->owner
.port
;
565 if ((! portEnabled(port
) && port
->infoIs
!= Disabled
) || BEGIN
== this->State
) {
566 return STP_hop_2_state (this, DISABLED
);
569 switch (this->State
) {
572 return STP_hop_2_state (this, DISABLED
);
574 if (portEnabled(port
)) {
575 return STP_hop_2_state (this, AGED
);
580 return STP_hop_2_state (this, AGED
);
584 if (port
->selected
&& port
->updtInfo
) {
585 return STP_hop_2_state (this, UPDATE
);
590 return STP_hop_2_state (this, CURRENT
);
594 if (port
->selected
&& port
->updtInfo
) {
595 return STP_hop_2_state (this, UPDATE
);
598 if (Received
== port
->infoIs
&&
599 port
->rcvdInfoWhile
==0 &&
602 return STP_hop_2_state (this, AGED
);
604 if (port
->rcvdMsg
&& !port
->updtInfo
) {
605 return STP_hop_2_state (this, RECEIVE
);
610 switch (port
->rcvdInfo
) {
611 case SuperiorDesignatedInfo
:
612 return STP_hop_2_state (this, SUPERIOR_DESIGNATED
);
613 case RepeatedDesignatedInfo
:
614 return STP_hop_2_state (this, REPEATED_DESIGNATED
);
615 case InferiorDesignatedInfo
:
616 return STP_hop_2_state (this, INFERIOR_DESIGNATED
);
617 case InferiorRootAlternateInfo
:
618 return STP_hop_2_state (this, NOT_DESIGNATED
);
620 return STP_hop_2_state (this, OTHER
);
624 case SUPERIOR_DESIGNATED
:
625 return STP_hop_2_state (this, CURRENT
);
628 case REPEATED_DESIGNATED
:
629 return STP_hop_2_state (this, CURRENT
);
632 case INFERIOR_DESIGNATED
:
633 return STP_hop_2_state (this, CURRENT
);
637 return STP_hop_2_state (this, CURRENT
);
641 return STP_hop_2_state (this, CURRENT
);