You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

stp.c 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /*
  2. * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. *
  19. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <errno.h>
  25. #include <byteswap.h>
  26. #include <ipxe/netdevice.h>
  27. #include <ipxe/ethernet.h>
  28. #include <ipxe/iobuf.h>
  29. #include <ipxe/timer.h>
  30. #include <ipxe/stp.h>
  31. /** @file
  32. *
  33. * Spanning Tree Protocol (STP)
  34. *
  35. */
  36. /* Disambiguate the various error causes */
  37. #define ENOTSUP_PROTOCOL __einfo_error ( EINFO_ENOTSUP_PROTOCOL )
  38. #define EINFO_ENOTSUP_PROTOCOL \
  39. __einfo_uniqify ( EINFO_ENOTSUP, 0x02, \
  40. "Non-STP packet received" )
  41. #define ENOTSUP_VERSION __einfo_error ( EINFO_ENOTSUP_VERSION )
  42. #define EINFO_ENOTSUP_VERSION \
  43. __einfo_uniqify ( EINFO_ENOTSUP, 0x03, \
  44. "Legacy STP packet received" )
  45. #define ENOTSUP_TYPE __einfo_error ( EINFO_ENOTSUP_TYPE )
  46. #define EINFO_ENOTSUP_TYPE \
  47. __einfo_uniqify ( EINFO_ENOTSUP, 0x04, \
  48. "Non-RSTP packet received" )
  49. /**
  50. * Process incoming STP packets
  51. *
  52. * @v iobuf I/O buffer
  53. * @v netdev Network device
  54. * @v ll_source Link-layer source address
  55. * @v flags Packet flags
  56. * @ret rc Return status code
  57. */
  58. static int stp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
  59. const void *ll_dest __unused,
  60. const void *ll_source __unused,
  61. unsigned int flags __unused ) {
  62. struct stp_bpdu *stp;
  63. unsigned int hello;
  64. int rc;
  65. /* Sanity check */
  66. if ( iob_len ( iobuf ) < sizeof ( *stp ) ) {
  67. DBGC ( netdev, "STP %s received underlength packet (%zd "
  68. "bytes):\n", netdev->name, iob_len ( iobuf ) );
  69. DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
  70. rc = -EINVAL;
  71. goto done;
  72. }
  73. stp = iobuf->data;
  74. /* Ignore non-RSTP packets */
  75. if ( stp->protocol != htons ( STP_PROTOCOL ) ) {
  76. DBGC ( netdev, "STP %s ignoring non-STP packet (protocol "
  77. "%#04x)\n", netdev->name, ntohs ( stp->protocol ) );
  78. rc = -ENOTSUP_PROTOCOL;
  79. goto done;
  80. }
  81. if ( stp->version < STP_VERSION_RSTP ) {
  82. DBGC ( netdev, "STP %s received legacy STP packet (version "
  83. "%#02x)\n", netdev->name, stp->version );
  84. rc = -ENOTSUP_VERSION;
  85. goto done;
  86. }
  87. if ( stp->type != STP_TYPE_RSTP ) {
  88. DBGC ( netdev, "STP %s received non-RSTP packet (type %#02x)\n",
  89. netdev->name, stp->type );
  90. rc = -ENOTSUP_TYPE;
  91. goto done;
  92. }
  93. /* Dump information */
  94. DBGC2 ( netdev, "STP %s %s port %#04x flags %#02x hello %d delay %d\n",
  95. netdev->name, eth_ntoa ( stp->sender.mac ), ntohs ( stp->port ),
  96. stp->flags, ntohs ( stp->hello ), ntohs ( stp->delay ) );
  97. /* Check if port is forwarding */
  98. if ( ! ( stp->flags & STP_FL_FORWARDING ) ) {
  99. /* Port is not forwarding: block link for two hello times */
  100. DBGC ( netdev, "STP %s %s port %#04x flags %#02x is not "
  101. "forwarding\n",
  102. netdev->name, eth_ntoa ( stp->sender.mac ),
  103. ntohs ( stp->port ), stp->flags );
  104. hello = ( ntohs ( stp->hello ) * ( TICKS_PER_SEC / 256 ) );
  105. netdev_link_block ( netdev, ( hello * 2 ) );
  106. rc = -ENETUNREACH;
  107. goto done;
  108. }
  109. /* Success */
  110. if ( netdev_link_blocked ( netdev ) ) {
  111. DBGC ( netdev, "STP %s %s port %#04x flags %#02x is "
  112. "forwarding\n",
  113. netdev->name, eth_ntoa ( stp->sender.mac ),
  114. ntohs ( stp->port ), stp->flags );
  115. }
  116. netdev_link_unblock ( netdev );
  117. rc = 0;
  118. done:
  119. free_iob ( iobuf );
  120. return rc;
  121. }
  122. /**
  123. * Transcribe STP address
  124. *
  125. * @v net_addr STP address
  126. * @ret string "<STP>"
  127. *
  128. * This operation is meaningless for the STP protocol.
  129. */
  130. static const char * stp_ntoa ( const void *net_addr __unused ) {
  131. return "<STP>";
  132. }
  133. /** STP network protocol */
  134. struct net_protocol stp_protocol __net_protocol = {
  135. .name = "STP",
  136. .net_proto = htons ( ETH_P_STP ),
  137. .rx = stp_rx,
  138. .ntoa = stp_ntoa,
  139. };