rstp_procedures.c
Go to the documentation of this file.
1 /**
2  * @file rstp_procedures.c
3  * @brief RSTP state machine procedures
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2019-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneSTP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL RSTP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "rstp/rstp.h"
36 #include "rstp/rstp_procedures.h"
37 #include "rstp/rstp_conditions.h"
38 #include "rstp/rstp_bpdu.h"
39 #include "rstp/rstp_misc.h"
40 #include "debug.h"
41 
42 //Check TCP/IP stack configuration
43 #if (RSTP_SUPPORT == ENABLED)
44 
45 //Port roles
47 {
48  {STP_PORT_ROLE_DISABLED, "Disabled"},
49  {STP_PORT_ROLE_ROOT, "Root"},
50  {STP_PORT_ROLE_DESIGNATED, "Designated"},
51  {STP_PORT_ROLE_ALTERNATE, "Alternate"},
52  {STP_PORT_ROLE_BACKUP, "Backup"}
53 };
54 
55 
56 /**
57  * @brief Compare Spanning Tree information (17.21.1)
58  * @param[in] port Pointer to the bridge port context
59  * @param[in] newInfoIs Procedure's parameter
60  * @return Boolean
61  **/
62 
64 {
65  bool_t res;
66 
67  //Check the source of the Spanning Tree information
68  if(newInfoIs == RSTP_INFO_IS_RECEIVED &&
69  port->infoIs == RSTP_INFO_IS_RECEIVED &&
70  rstpComparePriority(&port->msgPriority, &port->portPriority) >= 0)
71  {
72  //The function returns TRUE if the procedure's parameter newInfoIs is
73  //Received, and infoIs is Received and the msgPriority vector is better
74  //than or the same as the portPriority vector
75  res = TRUE;
76  }
77  else if(newInfoIs == RSTP_INFO_IS_MINE &&
78  port->infoIs == RSTP_INFO_IS_MINE &&
79  rstpComparePriority(&port->designatedPriority, &port->portPriority) >= 0)
80  {
81  //The function returns TRUE if The procedure's parameter newInfoIs is
82  //Mine, and infoIs is Mine and the designatedPriority vector is better
83  //than or the same as the portPriority vector
84  res = TRUE;
85  }
86  else
87  {
88  //The function returns FALSE otherwise
89  res = FALSE;
90  }
91 
92  //Return boolean value
93  return res;
94 }
95 
96 
97 /**
98  * @brief Clear reselect for all ports of the bridge (17.21.2)
99  * @param[in] context Pointer to the RSTP bridge context
100  **/
101 
103 {
104  uint_t i;
105 
106  //Loop through the ports of the bridge
107  for(i = 0; i < context->numPorts; i++)
108  {
109  //Clear the reselect variable
110  context->ports[i].reselect = FALSE;
111  }
112 }
113 
114 
115 /**
116  * @brief Stop forwarding frames through the port (17.21.3)
117  * @param[in] port Pointer to the bridge port context
118  **/
119 
121 {
122  //Debug message
123  TRACE_INFO("Port %" PRIu8 ": Disable forwarding...\r\n", port->portIndex);
124 }
125 
126 
127 /**
128  * @brief Stop learning from frames received on the port (17.21.4)
129  * @param[in] port Pointer to the bridge port context
130  **/
131 
133 {
134  //Debug message
135  TRACE_INFO("Port %" PRIu8 ": Disable learning...\r\n", port->portIndex);
136 
137  //Update the state of the port
139 }
140 
141 
142 /**
143  * @brief Start forwarding frames through the port (17.21.5)
144  * @param[in] port Pointer to the bridge port context
145  **/
146 
148 {
149  //Debug message
150  TRACE_INFO("Port %" PRIu8 ": Enable forwarding...\r\n", port->portIndex);
151 
152  //Update the state of the port
154 
155  //Increment the number of times the port has transitioned from the Learning
156  //state to the Forwarding state
157  port->forwardTransitions++;
158 }
159 
160 
161 /**
162  * @brief Start learning from frames received on the port (17.21.6)
163  * @param[in] port Pointer to the bridge port context
164  **/
165 
167 {
168  //Debug message
169  TRACE_INFO("Port %" PRIu8 ": Enable learning...\r\n", port->portIndex);
170 
171  //Update the state of the port
173 }
174 
175 
176 /**
177  * @brief Update the value of tcWhile (17.21.7)
178  * @param[in] port Pointer to the bridge port context
179  **/
180 
182 {
183  //Check whether the value of tcWhile is zero
184  if(port->tcWhile == 0)
185  {
186  //Update the number of topology changes
188 
189  //Check whether sendRSTP is set
190  if(port->sendRstp)
191  {
192  //If the value of tcWhile is zero and sendRSTP is TRUE, this procedure
193  //sets the value of tcWhile to HelloTime plus one second and sets
194  //newInfo TRUE
195  port->tcWhile = rstpHelloTime(port) + 1;
196  port->newInfo = TRUE;
197  }
198  else
199  {
200  //If the value of tcWhile is zero and sendRSTP is FALSE, this procedure
201  //sets the value of tcWhile to the sum of the Max Age and Forward Delay
202  //components of rootTimes and does not change the value of newInfo
203  port->tcWhile = port->context->rootTimes.maxAge +
204  port->context->rootTimes.forwardDelay;
205  }
206  }
207  else
208  {
209  //Otherwise the procedure takes no action
210  }
211 }
212 
213 
214 /**
215  * @brief Decode message priority and timer values from the received BPDU (17.21.8)
216  * @param[in] port Pointer to the bridge port context
217  * @return State of the received Spanning Tree information
218  **/
219 
221 {
222  int_t res;
223  uint8_t role;
224  RstpRcvdInfo portInfo;
225  const RstpBpdu *bpdu;
226 
227  //Point to the received BPDU
228  bpdu = &port->context->bpdu;
229 
230  //Errata (refer to IEEE Std 802.1Q-2018, section 13.29.13)
231  if(bpdu->bpduType == RSTP_BPDU_TYPE_TCN)
232  {
233  //Set rcvdTcn if a TCN BPDU has been received
234  port->rcvdTcn = TRUE;
235  }
236 
237  //Extract the message priority values from the received BPDU storing them in
238  //the msgPriority variable
239  port->msgPriority.rootBridgeId.priority = ntohs(bpdu->rootId.priority);
240  port->msgPriority.rootBridgeId.addr = bpdu->rootId.addr;
241  port->msgPriority.rootPathCost = ntohl(bpdu->rootPathCost);
242  port->msgPriority.designatedBridgeId.priority = ntohs(bpdu->bridgeId.priority);
243  port->msgPriority.designatedBridgeId.addr = bpdu->bridgeId.addr;
244  port->msgPriority.designatedPortId = ntohs(bpdu->portId);
245 
246  //The fifth component of the message priority vector value is the port
247  //identifier of the port through which the message was received
248  port->msgPriority.bridgePortId = port->portId;
249 
250  //Extract the timer values from the received BPDU storing them in the msgTimes
251  //variable
252  port->msgTimes.messageAge = ntohs(bpdu->messageAge) / 256;
253  port->msgTimes.maxAge = ntohs(bpdu->maxAge) / 256;
254  port->msgTimes.forwardDelay = ntohs(bpdu->forwardDelay) / 256;
255  port->msgTimes.helloTime = ntohs(bpdu->helloTime) / 256;
256 
257  //Check BPDU type
258  if(bpdu->bpduType == RSTP_BPDU_TYPE_RST)
259  {
260  //Decode port role
261  role = bpdu->flags & RSTP_BPDU_FLAG_PORT_ROLE;
262  }
263  else if(bpdu->bpduType == RSTP_BPDU_TYPE_CONFIG)
264  {
265  //A Configuration BPDU explicitly conveys a Designated port role
267  }
268  else
269  {
270  //Unknown port role
272  }
273 
274  //Check port role
276  {
277  //Compare message priority and port priority vectors
278  res = rstpComparePriority(&port->msgPriority, &port->portPriority);
279 
280  //A message priority vector is superior to the port priority vector if,
281  //and only if, the message priority vector is better than the port
282  //priority vector, or the Designated Bridge Identifier Bridge Address and
283  //Designated Port Identifier Port Number components are the same
284  if(res < 0)
285  {
286  //Compare Designated Bridge Identifier Bridge Address and Designated
287  //Port Identifier Port Number components
288  if(rstpCompareBridgeAddr(&port->msgPriority.designatedBridgeId.addr,
289  &port->portPriority.designatedBridgeId.addr) == 0 &&
290  rstpComparePortNum(port->msgPriority.designatedPortId,
291  port->portPriority.designatedPortId) == 0)
292  {
293  //The message has been transmitted from the same Designated port as
294  //a previously received superior message
295  res = 1;
296  }
297  }
298 
299  //Check comparison result
300  if(res > 0)
301  {
302  //Return SuperiorDesignatedInfo if the message priority is superior to
303  //the port priority vector
305  }
306  else if(res == 0)
307  {
308  //Check whether any of the received timer parameter values (msgTimes)
309  //differ from those already held for the port (portTimes)
310  if(rstpCompareTimes(&port->msgTimes, &port->portTimes) != 0)
311  {
312  //Return SuperiorDesignatedInfo
314  }
315  else
316  {
317  //Return RepeatedDesignatedInfo
319  }
320  }
321  else
322  {
323  //Returns InferiorDesignatedInfo if the message priority vector is
324  //worse than the Port's port priority vector
326  }
327  }
328  else if(role == RSTP_BPDU_FLAG_PORT_ROLE_ROOT ||
330  {
331  //Compare message priority and port priority vectors
332  res = rstpComparePriority(&port->msgPriority, &port->portPriority);
333 
334  //Check comparison result
335  if(res <= 0)
336  {
337  //Return InferiorRootAlternateInfo if the received message conveys a
338  //Root Port, Alternate Port, or Backup Port Role and a message priority
339  //that is the same as or worse than the port priority vector
341  }
342  else
343  {
344  //Return OtherInfo
345  portInfo = RSTP_RCVD_INFO_OTHER;
346  }
347  }
348  else
349  {
350  //Otherwise, return OtherInfo
351  portInfo = RSTP_RCVD_INFO_OTHER;
352  }
353 
354  //Return the state of the received Spanning Tree information
355  return portInfo;
356 }
357 
358 
359 /**
360  * @brief Record agreement (17.21.9)
361  * @param[in] port Pointer to the bridge port context
362  **/
363 
365 {
366  const RstpBpdu *bpdu;
367 
368  //Point to the received BPDU
369  bpdu = &port->context->bpdu;
370 
371  //If rstpVersion is TRUE, operPointToPointMAC is TRUE, and the received
372  //Configuration Message has the Agreement flag set, the agreed flag is set
373  //and the proposing flag is cleared. Otherwise, the agreed flag is cleared
374  if(rstpVersion(port->context) && port->operPointToPointMac &&
375  (bpdu->flags & RSTP_BPDU_FLAG_AGREEMENT) != 0)
376  {
377  port->agreed = TRUE;
378  port->proposing = FALSE;
379  }
380  else
381  {
382  port->agreed = FALSE;
383  }
384 }
385 
386 
387 /**
388  * @brief Record dispute (17.21.10)
389  * @param[in] port Pointer to the bridge port context
390  **/
391 
393 {
394  const RstpBpdu *bpdu;
395 
396  //Point to the received BPDU
397  bpdu = &port->context->bpdu;
398 
399  //If an RST BPDU with the learning flag set has been received, the
400  //disputed variable is set and the agreed variable is cleared (refer
401  //to IEEE Std 802.1D-2004 errata)
402  if((bpdu->flags & RSTP_BPDU_FLAG_LEARNING) != 0)
403  {
404  port->disputed = TRUE;
405  port->agreed = FALSE;
406  }
407 }
408 
409 
410 /**
411  * @brief Record proposal (17.21.11)
412  * @param[in] port Pointer to the bridge port context
413  **/
414 
416 {
417  uint8_t role;
418  const RstpBpdu *bpdu;
419 
420  //Point to the received BPDU
421  bpdu = &port->context->bpdu;
422 
423  //Decode port role
424  role = bpdu->flags & RSTP_BPDU_FLAG_PORT_ROLE;
425 
426  //If the received Configuration Message conveys a Designated Port Role,
427  //and has the Proposal flag is set, the proposed flag is set. Otherwise,
428  //the proposed flag is not changed
430  {
431  if((bpdu->flags & RSTP_BPDU_FLAG_PROPOSAL) != 0)
432  {
433  port->proposed = TRUE;
434  }
435  }
436 }
437 
438 
439 /**
440  * @brief Record priority (17.21.12)
441  * @param[in] port Pointer to the bridge port context
442  **/
443 
445 {
446  //Set the components of the portPriority variable to the values of the
447  //corresponding msgPriority components
448  port->portPriority = port->msgPriority;
449 }
450 
451 
452 /**
453  * @brief Set portTimes variable (17.21.13)
454  * @param[in] port Pointer to the bridge port context
455  **/
456 
458 {
459  //Set portTimes' Message Age, Max Age, and Forward Delay to the received
460  //values held in the messageTimes parameter
461  port->portTimes.messageAge = port->msgTimes.messageAge;
462  port->portTimes.maxAge = port->msgTimes.maxAge;
463  port->portTimes.forwardDelay = port->msgTimes.forwardDelay;
464 
465  //Set portTimes' Hello Time to msgTimes' Hello Time if that is greater
466  //than the minimum specified value, and to that minimum otherwise
467  if(port->msgTimes.helloTime > RSTP_MIN_BRIDGE_HELLO_TIME)
468  {
469  port->portTimes.helloTime = port->msgTimes.helloTime;
470  }
471  else
472  {
473  port->portTimes.helloTime = RSTP_MIN_BRIDGE_HELLO_TIME;
474  }
475 }
476 
477 
478 /**
479  * @brief Set sync for all ports of the bridge (17.21.14)
480  * @param[in] context Pointer to the RSTP bridge context
481  **/
482 
484 {
485  uint_t i;
486 
487  //Loop through the ports of the bridge
488  for(i = 0; i < context->numPorts; i++)
489  {
490  //Set the sync variable
491  context->ports[i].sync = TRUE;
492  }
493 }
494 
495 
496 /**
497  * @brief Set reRoot for all ports of the bridge (17.21.15)
498  * @param[in] context Pointer to the RSTP bridge context
499  **/
500 
502 {
503  uint_t i;
504 
505  //Loop through the ports of the bridge
506  for(i = 0; i < context->numPorts; i++)
507  {
508  //Set the reRoot variable
509  context->ports[i].reRoot = TRUE;
510  }
511 }
512 
513 
514 /**
515  * @brief Set the selected variable for all ports of the bridge (17.21.16)
516  * @param[in] context Pointer to the RSTP bridge context
517  **/
518 
520 {
521  uint_t i;
522  bool_t reselect;
523 
524  //Check whether the reselect variable is TRUE for any port
525  for(reselect = FALSE, i = 0; i < context->numPorts; i++)
526  {
527  reselect |= context->ports[i].reselect;
528  }
529 
530  //Set the selected variable TRUE for all ports of the bridge if reselect
531  //is FALSE for all ports. If reselect is TRUE for any port, this procedure
532  //takes no action
533  if(!reselect)
534  {
535  //Loop through the ports of the bridge
536  for(i = 0; i < context->numPorts; i++)
537  {
538  //Set the selected variable
539  context->ports[i].selected = TRUE;
540  }
541  }
542 }
543 
544 
545 /**
546  * @brief Update rcvdTc, rcvdTcAck and rcvdTcn flags (17.21.17)
547  * @param[in] port Pointer to the bridge port context
548  **/
549 
551 {
552  const RstpBpdu *bpdu;
553 
554  //Point to the received BPDU
555  bpdu = &port->context->bpdu;
556 
557  //Check BPDU type
558  if(bpdu->bpduType == RSTP_BPDU_TYPE_CONFIG ||
559  bpdu->bpduType == RSTP_BPDU_TYPE_RST)
560  {
561  //Sets rcvdTc and/or rcvdTcAck if the Topology Change and/or Topology
562  //Change Acknowledgment flags, respectively, are set in a Configuration
563  //BPDU or RST BPDU
564  if((bpdu->flags & RSTP_BPDU_FLAG_TC) != 0)
565  {
566  port->rcvdTc = TRUE;
567  }
568 
569  if((bpdu->flags & RSTP_BPDU_FLAG_TC_ACK) != 0)
570  {
571  port->rcvdTcAck = TRUE;
572  }
573  }
574  else if(bpdu->bpduType == RSTP_BPDU_TYPE_TCN)
575  {
576  //Set rcvdTcn TRUE if the BPDU is a TCN BPDU
577  port->rcvdTcn = TRUE;
578  }
579  else
580  {
581  //Just for sanity
582  }
583 }
584 
585 
586 /**
587  * @brief Set tcProp for all ports except the port that called the procedure (17.21.18)
588  * @param[in] port Pointer to the bridge port context
589  **/
590 
592 {
593  uint_t i;
594  RstpBridgeContext *context;
595 
596  //Point to the RSTP bridge context
597  context = port->context;
598 
599  //Loop through the ports of the bridge
600  for(i = 0; i < context->numPorts; i++)
601  {
602  //Set tcProp for all ports except the port that called the procedure
603  if(&context->ports[i] != port)
604  {
605  context->ports[i].tcProp = TRUE;
606  }
607  }
608 }
609 
610 
611 /**
612  * @brief Transmit a Configuration BPDU (17.21.19)
613  * @param[in] port Pointer to the bridge port context
614  **/
615 
617 {
618  RstpBpdu bpdu;
619 
620  //Format Configuration BPDU
621  bpdu.protocolId = HTONS(STP_PROTOCOL_ID);
622  bpdu.protocolVersionId = STP_PROTOCOL_VERSION;
623  bpdu.bpduType = RSTP_BPDU_TYPE_CONFIG;
624  bpdu.flags = 0;
625 
626  //The Topology Change flag is set if tcWhile is non-zero for the port
627  if(port->tcWhile != 0)
628  {
629  bpdu.flags |= RSTP_BPDU_FLAG_TC;
630  }
631 
632  //The Topology Change Acknowledgement flag is set to the value of tcAck
633  //for the port
634  if(port->tcAck)
635  {
636  bpdu.flags |= RSTP_BPDU_FLAG_TC_ACK;
637  }
638 
639  //The components of the message priority vector conveyed in the BPDU are set
640  //to the value of designatedPriority for this port
641  bpdu.rootId.priority = htons(port->designatedPriority.rootBridgeId.priority);
642  bpdu.rootId.addr = port->designatedPriority.rootBridgeId.addr;
643  bpdu.rootPathCost = htonl(port->designatedPriority.rootPathCost);
644  bpdu.bridgeId.priority = htons(port->designatedPriority.designatedBridgeId.priority);
645  bpdu.bridgeId.addr = port->designatedPriority.designatedBridgeId.addr;
646  bpdu.portId = htons(port->designatedPriority.designatedPortId);
647 
648  //The value of the Message Age, Max Age, Fwd Delay, and Hello Time parameters
649  //conveyed in the BPDU are set to the values held in designatedTimes for the
650  //port
651  bpdu.messageAge = htons(port->designatedTimes.messageAge * 256);
652  bpdu.maxAge = htons(port->designatedTimes.maxAge * 256);
653  bpdu.helloTime = htons(port->designatedTimes.helloTime * 256);
654  bpdu.forwardDelay = htons(port->designatedTimes.forwardDelay * 256);
655 
656  //Send BPDU
658 }
659 
660 
661 /**
662  * @brief Transmit a Rapid Spanning Tree BPDU (17.21.20)
663  * @param[in] port Pointer to the bridge port context
664  **/
665 
667 {
668  RstpBpdu bpdu;
669 
670  //Format Rapid Spanning Tree BPDU
671  bpdu.protocolId = HTONS(STP_PROTOCOL_ID);
672  bpdu.protocolVersionId = RSTP_PROTOCOL_VERSION;
673  bpdu.bpduType = RSTP_BPDU_TYPE_RST;
674  bpdu.flags = 0;
675 
676  //The Port Role in the BPDU is set to the current value of the role variable
677  //for the transmitting port
678  if(port->role == STP_PORT_ROLE_ALTERNATE ||
679  port->role == STP_PORT_ROLE_BACKUP)
680  {
681  //Alternate or Backup port role
683  }
684  else if(port->role == STP_PORT_ROLE_ROOT)
685  {
686  //Root port role
687  bpdu.flags |= RSTP_BPDU_FLAG_PORT_ROLE_ROOT;
688  }
689  else if(port->role == STP_PORT_ROLE_DESIGNATED)
690  {
691  //Designated port role
693  }
694  else
695  {
696  //The Unknown value of Port Role cannot be generated by a valid
697  //implementation
698  bpdu.flags |= RSTP_BPDU_FLAG_PORT_ROLE_UNKNOWN;
699  }
700 
701  //The Agreement and Proposal flags in the BPDU are set to the values of the
702  //agree and proposing variables for the transmitting port, respectively
703  if(port->agree)
704  {
705  bpdu.flags |= RSTP_BPDU_FLAG_AGREEMENT;
706  }
707 
708  if(port->proposing)
709  {
710  bpdu.flags |= RSTP_BPDU_FLAG_PROPOSAL;
711  }
712 
713  //The Topology Change flag is set if tcWhile is non-zero for the port. The
714  //topology change acknowledge flag in the BPDU is never used and is set to
715  //zero
716  if(port->tcWhile != 0)
717  {
718  bpdu.flags |= RSTP_BPDU_FLAG_TC;
719  }
720 
721  //The Learning and Forwarding flags in the BPDU are set to the values of the
722  //learning and forwarding variables for the transmitting port, respectively
723  if(port->learning)
724  {
725  bpdu.flags |= RSTP_BPDU_FLAG_LEARNING;
726  }
727 
728  if(port->forwarding)
729  {
730  bpdu.flags |= RSTP_BPDU_FLAG_FORWARDING;
731  }
732 
733  //The components of the message priority vector conveyed in the BPDU are set
734  //to the value of designatedPriority for this port
735  bpdu.rootId.priority = htons(port->designatedPriority.rootBridgeId.priority);
736  bpdu.rootId.addr = port->designatedPriority.rootBridgeId.addr;
737  bpdu.rootPathCost = htonl(port->designatedPriority.rootPathCost);
738  bpdu.bridgeId.priority = htons(port->designatedPriority.designatedBridgeId.priority);
739  bpdu.bridgeId.addr = port->designatedPriority.designatedBridgeId.addr;
740  bpdu.portId = htons(port->designatedPriority.designatedPortId);
741 
742  //The value of the Message Age, Max Age, Fwd Delay, and Hello Time parameters
743  //conveyed in the BPDU are set to the values held in designatedTimes for the
744  //port
745  bpdu.messageAge = htons(port->designatedTimes.messageAge * 256);
746  bpdu.maxAge = htons(port->designatedTimes.maxAge * 256);
747  bpdu.helloTime = htons(port->designatedTimes.helloTime * 256);
748  bpdu.forwardDelay = htons(port->designatedTimes.forwardDelay * 256);
749 
750  //The Version 1 Length field takes the value 0, which indicates that there
751  //is no Version 1 protocol information present
752  bpdu.version1Length = 0;
753 
754  //Send BPDU
756 }
757 
758 
759 /**
760  * @brief Transmit a Topology Change Notification BPDU (17.21.21)
761  * @param[in] port Pointer to the bridge port context
762  **/
763 
765 {
766  RstpBpdu bpdu;
767 
768  //Format Topology Change Notification BPDU
769  bpdu.protocolId = HTONS(STP_PROTOCOL_ID);
770  bpdu.protocolVersionId = STP_PROTOCOL_VERSION;
771  bpdu.bpduType = RSTP_BPDU_TYPE_TCN;
772 
773  //Send BPDU
775 }
776 
777 
778 /**
779  * @brief Update rcvdSTP and rcvdRSTP variables depending on BPDU version (17.21.22)
780  * @param[in] port Pointer to the bridge port context
781  **/
782 
784 {
785  const RstpBpdu *bpdu;
786 
787  //Point to the received BPDU
788  bpdu = &port->context->bpdu;
789 
790  //Check BPDU type
791  if(bpdu->bpduType == RSTP_BPDU_TYPE_TCN ||
792  bpdu->bpduType == RSTP_BPDU_TYPE_CONFIG)
793  {
794  //Sets rcvdSTP TRUE if the BPDU received is a version 0 or version 1 TCN
795  //or a Configuration BPDU
796  port->rcvdStp = TRUE;
797  }
798  else if(bpdu->bpduType == RSTP_BPDU_TYPE_RST)
799  {
800  //Set rcvdRSTP TRUE if the received BPDU is an RST BPDU
801  port->rcvdRstp = TRUE;
802  }
803  else
804  {
805  //Just for sanity
806  }
807 }
808 
809 
810 /**
811  * @brief Update the Received Info timer (17.21.23)
812  * @param[in] port Pointer to the bridge port context
813  **/
814 
816 {
817  //The value assigned to rcvdInfoWhile is the three times the Hello Time,
818  //if Message Age, incremented by 1 second and rounded to the nearest whole
819  //second, does not exceed Max Age, and is zero otherwise. The values of
820  //Message Age, Max Age, and Hello Time used in this calculation are taken
821  //from portTimes
822  if((port->portTimes.messageAge + 1) <= port->portTimes.maxAge)
823  {
824  port->rcvdInfoWhile = (3 * port->portTimes.helloTime) + 1;
825  }
826  else
827  {
828  port->rcvdInfoWhile = 0;
829  }
830 }
831 
832 
833 /**
834  * @brief Set the selectedRole to DisabledPort for all ports of the bridge (17.21.24)
835  * @param[in] context Pointer to the RSTP bridge context
836  **/
837 
839 {
840  uint_t i;
841 
842  //Loop through the ports of the bridge
843  for(i = 0; i < context->numPorts; i++)
844  {
845  //Set the selectedRole variable to DisabledPort
846  context->ports[i].selectedRole = STP_PORT_ROLE_DISABLED;
847  }
848 }
849 
850 
851 /**
852  * @brief Update spanning tree information and port roles (17.21.25)
853  * @param[in] context Pointer to the RSTP bridge context
854  **/
855 
857 {
858  uint_t i;
860  RstpBridgePort *rootPort;
861  RstpPriority rootPathPriority;
862 
863  //Initialize bridge's root priority vector
864  context->rootPriority = context->bridgePriority;
865  context->rootPortId = context->bridgePriority.bridgePortId;
866 
867  //Initialize bridge's rootTimes parameter
868  context->rootTimes = context->bridgeTimes;
869 
870  //The port the root priority vector is derived from
871  rootPort = NULL;
872 
873  //Loop through the ports of the bridge
874  for(i = 0; i < context->numPorts; i++)
875  {
876  //Point to the current bridge port
877  port = &context->ports[i];
878 
879  //Calculate the root path priority vector for each port that has a port
880  //priority vector (portPriority plus portId) recorded from a received
881  //message and not aged out
882  if(port->infoIs == RSTP_INFO_IS_RECEIVED)
883  {
884  //A root path priority vector can be calculated from a received port
885  //priority vector, by adding the receiving port's path cost to the
886  //Root Path Cost component
887  rootPathPriority = port->portPriority;
888  rootPathPriority.rootPathCost += port->portPathCost;
889 
890  //The bridge's root priority vector (rootPriority plus rootPortId) is
891  //chosen as the best of the set of priority vectors comprising the
892  //bridge priority vector (BridgePriority) and all the calculated root
893  //path priority vectors whose DesignatedBridgeID Bridge Address
894  //component is not equal to that component of the Bridge's own bridge
895  //priority vector
896  if(rstpCompareBridgeAddr(&rootPathPriority.designatedBridgeId.addr,
897  &context->bridgePriority.designatedBridgeId.addr) != 0)
898  {
899  //Calculate the best priority vector
900  if(rstpComparePriority(&rootPathPriority, &context->rootPriority) > 0)
901  {
902  //Save current root path priority vector
903  context->rootPriority = rootPathPriority;
904  context->rootPortId = rootPathPriority.bridgePortId;
905 
906  //Save the port the root priority vector is now derived from
907  rootPort = port;
908 
909  //Set the bridge's rootTimes parameter to portTimes for the port
910  //associated with the selected root priority vector, with the
911  //Message Age component incremented by 1 second and rounded to
912  //the nearest whole second
913  context->rootTimes = port->portTimes;
914  context->rootTimes.messageAge++;
915  }
916  }
917  }
918  }
919 
920  //Loop through the ports of the bridge
921  for(i = 0; i < context->numPorts; i++)
922  {
923  //Point to the current bridge port
924  port = &context->ports[i];
925 
926  //The designated priority vector is the root priority vector with the
927  //Bridge Identifier substituted for the DesignatedBridgeID and the
928  //Port Identifier substituted for the DesignatedPortID and BridgePortID
929  //components
930  port->designatedPriority.rootBridgeId = context->rootPriority.rootBridgeId;
931  port->designatedPriority.rootPathCost = context->rootPriority.rootPathCost;
932  port->designatedPriority.designatedBridgeId = context->bridgeId;
933  port->designatedPriority.designatedPortId = port->portId;
934  port->designatedPriority.bridgePortId = port->portId;
935 
936  //The designatedTimes for each port is set equal to the value of rootTimes
937  //except for the Hello Time component, which is set equal to BridgeTimes'
938  //Hello Time
939  port->designatedTimes = context->rootTimes;
940  port->designatedTimes.helloTime = context->bridgeTimes.helloTime;
941  }
942 
943  //The port role for each port is assigned, and its port priority vector and
944  //Spanning Tree timer information are updated
945  for(i = 0; i < context->numPorts; i++)
946  {
947  //Point to the current bridge port
948  port = &context->ports[i];
949 
950  //The port role for each port is assigned
951  if(port->infoIs == RSTP_INFO_IS_DISABLED)
952  {
953  //If the Port is Disabled, selectedRole is set to DisabledPort
954  port->selectedRole = STP_PORT_ROLE_DISABLED;
955  }
956  else if(port->infoIs == RSTP_INFO_IS_AGED)
957  {
958  //If the port priority vector information was aged, updtInfo is set
959  //and selectedRole is set to DesignatedPort
960  port->selectedRole = STP_PORT_ROLE_DESIGNATED;
961  port->updtInfo = TRUE;
962  }
963  else if(port->infoIs == RSTP_INFO_IS_MINE)
964  {
965  //If the port priority vector was derived from another port on the
966  //bridge or from the bridge itself as the Root bridge, selectedRole
967  //is set to DesignatedPort
968  port->selectedRole = STP_PORT_ROLE_DESIGNATED;
969 
970  //Additionally, updtInfo is set if the port priority vector differs
971  //from the designated priority vector or the port's associated timer
972  //parameters differ from those for the Root port
973  if(rstpComparePriority(&port->portPriority, &port->designatedPriority) != 0 ||
974  rstpCompareTimes(&port->portTimes, &context->rootTimes) != 0)
975  {
976  port->updtInfo = TRUE;
977  }
978  }
979  else if(port->infoIs == RSTP_INFO_IS_RECEIVED)
980  {
981  //Check whether the root priority vector is derived from port priority
982  //vector
983  if(port == rootPort)
984  {
985  //If the port priority vector was received in a Configuration
986  //message and is not aged, and the root priority vector is now
987  //derived from it, selectedRole is set to RootPort and updtInfo
988  //is reset
989  port->selectedRole = STP_PORT_ROLE_ROOT;
990  port->updtInfo = FALSE;
991  }
992  else
993  {
994  //Check whether the designated priority vector is better than the
995  //port priority vector
996  if(rstpComparePriority(&port->designatedPriority, &port->portPriority) > 0)
997  {
998  //selectedRole is set to DesignatedPort and updtInfo is set
999  port->selectedRole = STP_PORT_ROLE_DESIGNATED;
1000  port->updtInfo = TRUE;
1001  }
1002  else
1003  {
1004  MacAddr *addr;
1005  uint16_t portId;
1006 
1007  //Retrieve the designated bridge and designated port components
1008  //of the port priority vector
1009  addr = &port->portPriority.designatedBridgeId.addr;
1010  portId = port->portPriority.designatedPortId;
1011 
1012  //Check whether the designated bridge and designated port
1013  //components of the port priority vector reflect another port
1014  //on this bridge
1015  if(rstpCompareBridgeAddr(addr, &context->bridgeId.addr) == 0 &&
1016  rstpGetBridgePort(context, portId) != NULL)
1017  {
1018  //selectedRole is set to BackupPort and updtInfo is reset
1019  port->selectedRole = STP_PORT_ROLE_BACKUP;
1020  port->updtInfo = FALSE;
1021  }
1022  else
1023  {
1024  //selectedRole is set to AlternatePort and updtInfo is reset
1025  port->selectedRole = STP_PORT_ROLE_ALTERNATE;
1026  port->updtInfo = FALSE;
1027  }
1028  }
1029  }
1030  }
1031  else
1032  {
1033  //Just for sanity
1034  }
1035  }
1036 
1037  //Loop through the ports of the bridge
1038  for(i = 0; i < context->numPorts; i++)
1039  {
1040  //Point to the current bridge port
1041  port = &context->ports[i];
1042 
1043  //Display selected port role
1044  TRACE_DEBUG("Port %" PRIu8 ": Selected role is %s\r\n", port->portIndex,
1046  }
1047 }
1048 
1049 #endif
signed int int_t
Definition: compiler_port.h:49
unsigned int uint_t
Definition: compiler_port.h:50
int bool_t
Definition: compiler_port.h:53
#define HTONS(value)
Definition: cpu_endian.h:410
#define ntohl(value)
Definition: cpu_endian.h:422
#define htonl(value)
Definition: cpu_endian.h:414
#define htons(value)
Definition: cpu_endian.h:413
#define ntohs(value)
Definition: cpu_endian.h:421
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_INFO(...)
Definition: debug.h:95
uint16_t port
Definition: dns_common.h:267
MacAddr
Definition: ethernet.h:195
uint8_t portId[]
Definition: lldp_tlv.h:254
Ipv4Addr addr
Definition: nbns_common.h:123
@ SWITCH_PORT_STATE_FORWARDING
Definition: nic.h:140
@ SWITCH_PORT_STATE_BLOCKING
Definition: nic.h:137
@ SWITCH_PORT_STATE_LEARNING
Definition: nic.h:139
#define arraysize(a)
Definition: os_port.h:71
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
const uint8_t res[]
RSTP (Rapid Spanning Tree Protocol)
RstpInfoIs
Origin/state of the port's Spanning Tree information.
Definition: rstp.h:242
@ RSTP_INFO_IS_MINE
Definition: rstp.h:245
@ RSTP_INFO_IS_RECEIVED
Definition: rstp.h:244
@ RSTP_INFO_IS_DISABLED
Definition: rstp.h:243
@ RSTP_INFO_IS_AGED
Definition: rstp.h:246
#define RstpBridgeContext
Definition: rstp.h:36
#define RstpBridgePort
Definition: rstp.h:40
RstpRcvdInfo
State of the received Spanning Tree information.
Definition: rstp.h:228
@ RSTP_RCVD_INFO_SUPERIOR_DESIGNATED
Definition: rstp.h:229
@ RSTP_RCVD_INFO_INFERIOR_ROOT_ALTERNATE
Definition: rstp.h:232
@ RSTP_RCVD_INFO_OTHER
Definition: rstp.h:233
@ RSTP_RCVD_INFO_INFERIOR_DESIGNATED
Definition: rstp.h:231
@ RSTP_RCVD_INFO_REPEATED_DESIGNATED
Definition: rstp.h:230
#define RSTP_MIN_BRIDGE_HELLO_TIME
Definition: rstp.h:114
error_t rstpSendBpdu(RstpBridgePort *port, const RstpBpdu *bpdu, size_t length)
Send bridge protocol data unit.
Definition: rstp_bpdu.c:308
BPDU processing.
#define RSTP_RST_BPDU_SIZE
Definition: rstp_bpdu.h:40
@ RSTP_BPDU_FLAG_PORT_ROLE_UNKNOWN
Definition: rstp_bpdu.h:73
@ RSTP_BPDU_FLAG_PORT_ROLE_ROOT
Definition: rstp_bpdu.h:75
@ RSTP_BPDU_FLAG_AGREEMENT
Definition: rstp_bpdu.h:79
@ RSTP_BPDU_FLAG_TC_ACK
Definition: rstp_bpdu.h:80
@ RSTP_BPDU_FLAG_LEARNING
Definition: rstp_bpdu.h:77
@ RSTP_BPDU_FLAG_PORT_ROLE_DESIGNATED
Definition: rstp_bpdu.h:76
@ RSTP_BPDU_FLAG_PORT_ROLE_ALT_BACKUP
Definition: rstp_bpdu.h:74
@ RSTP_BPDU_FLAG_PORT_ROLE
Definition: rstp_bpdu.h:72
@ RSTP_BPDU_FLAG_FORWARDING
Definition: rstp_bpdu.h:78
@ RSTP_BPDU_FLAG_PROPOSAL
Definition: rstp_bpdu.h:71
@ RSTP_BPDU_FLAG_TC
Definition: rstp_bpdu.h:70
#define RSTP_CONFIG_BPDU_SIZE
Definition: rstp_bpdu.h:39
RstpBpdu
Definition: rstp_bpdu.h:111
@ RSTP_BPDU_TYPE_TCN
Definition: rstp_bpdu.h:59
@ RSTP_BPDU_TYPE_RST
Definition: rstp_bpdu.h:60
@ RSTP_BPDU_TYPE_CONFIG
Definition: rstp_bpdu.h:58
#define RSTP_TCN_BPDU_SIZE
Definition: rstp_bpdu.h:38
uint_t rstpHelloTime(RstpBridgePort *port)
HelloTime variable evaluation (17.20.7)
bool_t rstpVersion(RstpBridgeContext *context)
rstpVersion condition (17.20.11)
RSTP state machine conditions.
void rstpUpdateTopologyChangeCount(RstpBridgeContext *context)
Update the number of topology changes.
Definition: rstp_misc.c:394
void rstpUpdatePortState(RstpBridgePort *port, SwitchPortState state)
Set port state.
Definition: rstp_misc.c:495
int_t rstpComparePortNum(uint16_t portId1, uint16_t portId2)
Compare port numbers.
Definition: rstp_misc.c:219
RstpBridgePort * rstpGetBridgePort(RstpBridgeContext *context, uint16_t portId)
Retrieve the port that matches the specified port number.
Definition: rstp_misc.c:187
const char_t * rstpGetParamName(uint_t value, const RstpParamName *paramList, size_t paramListLen)
Convert a parameter to string representation.
Definition: rstp_misc.c:883
int_t rstpComparePriority(const RstpPriority *p1, const RstpPriority *p2)
Compare priority vectors.
Definition: rstp_misc.c:302
int_t rstpCompareBridgeAddr(const MacAddr *addr1, const MacAddr *addr2)
Compare bridge addresses.
Definition: rstp_misc.c:256
int_t rstpCompareTimes(const RstpTimes *t1, const RstpTimes *t2)
Compare timer parameter values.
Definition: rstp_misc.c:367
RSTP helper functions.
void rstpSetSyncTree(RstpBridgeContext *context)
Set sync for all ports of the bridge (17.21.14)
void rstpUpdtRcvdInfoWhile(RstpBridgePort *port)
Update the Received Info timer (17.21.23)
bool_t rstpBetterOrSameInfo(RstpBridgePort *port, RstpInfoIs newInfoIs)
Compare Spanning Tree information (17.21.1)
void rstpNewTcWhile(RstpBridgePort *port)
Update the value of tcWhile (17.21.7)
void rstpEnableLearning(RstpBridgePort *port)
Start learning from frames received on the port (17.21.6)
void rstpRecordDispute(RstpBridgePort *port)
Record dispute (17.21.10)
void rstpRecordTimes(RstpBridgePort *port)
Set portTimes variable (17.21.13)
void rstpUpdtBpduVersion(RstpBridgePort *port)
Update rcvdSTP and rcvdRSTP variables depending on BPDU version (17.21.22)
void rstpDisableForwarding(RstpBridgePort *port)
Stop forwarding frames through the port (17.21.3)
void rstpRecordProposal(RstpBridgePort *port)
Record proposal (17.21.11)
void rstpUpdtRolesTree(RstpBridgeContext *context)
Update spanning tree information and port roles (17.21.25)
void rstpDisableLearning(RstpBridgePort *port)
Stop learning from frames received on the port (17.21.4)
void rstpSetReRootTree(RstpBridgeContext *context)
Set reRoot for all ports of the bridge (17.21.15)
void rstpUpdtRoleDisabledTree(RstpBridgeContext *context)
Set the selectedRole to DisabledPort for all ports of the bridge (17.21.24)
void rstpSetSelectedTree(RstpBridgeContext *context)
Set the selected variable for all ports of the bridge (17.21.16)
void rstpRecordAgreement(RstpBridgePort *port)
Record agreement (17.21.9)
void rstpSetTcFlags(RstpBridgePort *port)
Update rcvdTc, rcvdTcAck and rcvdTcn flags (17.21.17)
void rstpTxTcn(RstpBridgePort *port)
Transmit a Topology Change Notification BPDU (17.21.21)
RstpRcvdInfo rstpRcvInfo(RstpBridgePort *port)
Decode message priority and timer values from the received BPDU (17.21.8)
void rstpTxConfig(RstpBridgePort *port)
Transmit a Configuration BPDU (17.21.19)
void rstpRecordPriority(RstpBridgePort *port)
Record priority (17.21.12)
void rstpEnableForwarding(RstpBridgePort *port)
Start forwarding frames through the port (17.21.5)
const RstpParamName rstpPortRoles[]
void rstpTxRstp(RstpBridgePort *port)
Transmit a Rapid Spanning Tree BPDU (17.21.20)
void rstpSetTcPropTree(RstpBridgePort *port)
Set tcProp for all ports except the port that called the procedure (17.21.18)
void rstpClearReselectTree(RstpBridgeContext *context)
Clear reselect for all ports of the bridge (17.21.2)
RSTP state machine procedures.
#define STP_PROTOCOL_ID
Definition: stp_common.h:80
@ STP_PROTOCOL_VERSION
STP version.
Definition: stp_common.h:97
@ RSTP_PROTOCOL_VERSION
RSTP version.
Definition: stp_common.h:98
@ STP_PORT_ROLE_BACKUP
Definition: stp_common.h:128
@ STP_PORT_ROLE_ALTERNATE
Definition: stp_common.h:127
@ STP_PORT_ROLE_ROOT
Definition: stp_common.h:125
@ STP_PORT_ROLE_DESIGNATED
Definition: stp_common.h:126
@ STP_PORT_ROLE_DISABLED
Definition: stp_common.h:124
Parameter value/name binding.
Definition: rstp_misc.h:48
Spanning Tree priority vector.
Definition: rstp.h:280
uint16_t bridgePortId
Definition: rstp.h:285
StpBridgeId designatedBridgeId
Definition: rstp.h:283
uint32_t rootPathCost
Definition: rstp.h:282