Coverage Report

Created: 2026-11-12 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/header/StpLayer.h
Line
Count
Source
1
#pragma once
2
3
#include "Layer.h"
4
#include "MacAddress.h"
5
#include <cstring>
6
7
/// @file
8
9
/// @namespace pcpp
10
/// @brief The main namespace for the PcapPlusPlus lib
11
namespace pcpp
12
{
13
  /// @struct stp_tcn_bpdu
14
  /// Represents payload of network changes announcements of BPDU
15
#pragma pack(push, 1)
16
  struct stp_tcn_bpdu
17
  {
18
    /// Protocol ID. Fixed at 0x0, which represents IEEE 802.1d
19
    uint16_t protoId;
20
    /// Protocol version. 0x0 for STP, 0x2 for RSTP, 0x3 for MSTP
21
    uint8_t version;
22
    /// Type of the BPDU. 0x0 for configuration, 0x2 for RSTP/MSTP, 0x80 for TCN
23
    uint8_t type;
24
  };
25
#pragma pack(pop)
26
  static_assert(sizeof(stp_tcn_bpdu) == 4, "stp_tcn_bpdu size is not 4 bytes");
27
28
  /// Spanning Tree protocol common header
29
  typedef stp_tcn_bpdu stp_header;
30
  static_assert(sizeof(stp_header) == 4, "stp_header size is not 4 bytes");
31
32
  /// @struct stp_conf_bpdu
33
  /// Represents payload configuration of BPDU for STP
34
#pragma pack(push, 1)
35
  struct stp_conf_bpdu : stp_tcn_bpdu
36
  {
37
    /// Flag for indicate purpose of BPDU
38
    uint8_t flag;
39
    /// Root bridge ID
40
    uint64_t rootId;
41
    /// Cost of path
42
    uint32_t pathCost;
43
    /// Bridge ID
44
    uint64_t bridgeId;
45
    /// Port ID
46
    uint16_t portId;
47
    /// Age of the BPDU
48
    uint16_t msgAge;
49
    /// Maximum age of the BPDU
50
    uint16_t maxAge;
51
    /// BPDU transmission interval
52
    uint16_t helloTime;
53
    /// Delay for STP
54
    uint16_t forwardDelay;
55
  };
56
#pragma pack(pop)
57
  static_assert(sizeof(stp_conf_bpdu) == 35, "stp_conf_bpdu size is not 35 bytes");
58
59
  /// @struct rstp_conf_bpdu
60
  /// Represents payload configuration of BPDU for Rapid STP (RSTP)
61
#pragma pack(push, 1)
62
  struct rstp_conf_bpdu : stp_conf_bpdu
63
  {
64
    /// Version1 length. The value is 0x0
65
    uint8_t version1Len;
66
  };
67
#pragma pack(pop)
68
  static_assert(sizeof(rstp_conf_bpdu) == 36, "rstp_conf_bpdu size is not 36 bytes");
69
70
  /// @struct mstp_conf_bpdu
71
  /// Represents payload configuration of BPDU for Multiple STP (MSTP)
72
#pragma pack(push, 1)
73
  struct mstp_conf_bpdu : rstp_conf_bpdu
74
  {
75
    /// Version3 length.
76
    uint16_t version3Len;
77
    /// Configuration id format selector
78
    uint8_t mstConfigFormatSelector;
79
    /// Configuration id name
80
    uint8_t mstConfigName[32];
81
    /// Configuration id revision
82
    uint16_t mstConfigRevision;
83
    /// Configuration id digest
84
    uint8_t mstConfigDigest[16];
85
    /// CIST internal root path cost
86
    uint32_t irpc;
87
    /// CIST bridge id
88
    uint64_t cistBridgeId;
89
    /// CIST remaining hop count
90
    uint8_t remainId;
91
  };
92
#pragma pack(pop)
93
  static_assert(sizeof(mstp_conf_bpdu) == 102, "mstp_conf_bpdu size is not 102 bytes");
94
95
  /// @struct msti_conf_msg
96
  /// Represents MSTI configuration messages. Each message contains 16 bytes and MSTP can contain 0 to 64 MSTI
97
  /// messages.
98
#pragma pack(push, 1)
99
  struct msti_conf_msg
100
  {
101
    /// MSTI flags
102
    uint8_t flags;
103
    /// Regional root switching id (Priority (4 bits) + ID (12 bits) + Regional root (48 bits - MAC address))
104
    uint64_t regionalRootId;
105
    /// Total path cost from local port to regional port
106
    uint32_t pathCost;
107
    /// Priority value of switching device
108
    uint8_t bridgePriority;
109
    /// Priority value of port
110
    uint8_t portPriority;
111
    /// Remaining hops of BPDU
112
    uint8_t remainingHops;
113
  };
114
#pragma pack(pop)
115
  static_assert(sizeof(msti_conf_msg) == 16, "msti_conf_msg size is not 16 bytes");
116
117
  /// @class StpLayer
118
  /// Represents an Spanning Tree Protocol Layer
119
  class StpLayer : public Layer
120
  {
121
  protected:
122
    StpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
123
4.63k
        : Layer(data, dataLen, prevLayer, packet, STP)
124
4.63k
    {}
125
126
    explicit StpLayer(size_t dataLen)
127
0
    {
128
0
      allocData(dataLen);
129
0
      m_Protocol = STP;
130
0
    }
131
132
    static pcpp::MacAddress IDtoMacAddress(uint64_t id);
133
    static uint64_t macAddressToID(const pcpp::MacAddress& addr);
134
135
    void serializeLayer(ObjectScope& serializer) const override;
136
137
  public:
138
    /// @brief Fields serialized for StpLayer, including its base layer fields.
139
    struct SerializedFields : Layer::SerializedFields
140
    {
141
      /// @return All field descriptors, including the inherited fields
142
      static std::vector<FieldDescriptor> all()
143
0
      {
144
0
        auto result = Layer::SerializedFields::all();
145
0
        std::initializer_list<FieldDescriptor> extra{ ProtoId, Version, Type };
146
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
147
0
        return result;
148
0
      }
149
150
      /// @brief BPDU protocol identifier, as an unsigned integer in host byte order.
151
      static const FieldDescriptor ProtoId;
152
153
      /// @brief BPDU protocol version.
154
      static const FieldDescriptor Version;
155
156
      /// @brief BPDU type (0 for configuration, 2 for RSTP/MSTP, 128 for TCN).
157
      static const FieldDescriptor Type;
158
159
      /// @brief Maximum field ID used by this layer.
160
      static constexpr uint16_t MaxStpFieldID = Layer::SerializedFields::MaxID + 3;
161
    };
162
163
    /// STP protocol uses "01:80:C2:00:00:00" multicast address as destination MAC
164
    static pcpp::MacAddress StpMulticastDstMAC;
165
    /// STP Uplink Fast protocol uses "01:00:0C:CD:CD:CD" as destination MAC
166
    static pcpp::MacAddress StpUplinkFastMulticastDstMAC;
167
168
    /// Get a pointer to base Spanning tree header
169
    /// @return A pointer to spanning tree header
170
    stp_header* getStpHeader() const
171
0
    {
172
0
      return reinterpret_cast<stp_header*>(m_Data);
173
0
    }
174
175
    /// Returns the protocol id. Fixed at 0x0 for STP messages which represents IEEE 802.1d
176
    /// @return ID of the protocol
177
    uint16_t getProtoId() const
178
0
    {
179
0
      return getStpHeader()->protoId;
180
0
    }
181
182
    /// Sets the protocol id
183
    /// @param[in] value ID of the protocol
184
185
    void setProtoId(uint16_t value)
186
0
    {
187
0
      getStpHeader()->protoId = value;
188
0
    }
189
190
    /// Returns the version. Fixed at 0x0 for STP messages
191
    /// @return Version number
192
    uint8_t getVersion() const
193
0
    {
194
0
      return getStpHeader()->version;
195
0
    }
196
197
    /// Sets the version
198
    /// @param[in] value Version number
199
    void setVersion(uint8_t value)
200
0
    {
201
0
      getStpHeader()->version = value;
202
0
    }
203
204
    /// Returns the type of configuration message.
205
    /// @return Type of configuration message
206
    uint8_t getType() const
207
0
    {
208
0
      return getStpHeader()->type;
209
0
    }
210
211
    /// Sets the type of configuration message
212
    /// @param[in] value Type of configuration message
213
    void setType(uint8_t value)
214
0
    {
215
0
      getStpHeader()->type = value;
216
0
    }
217
218
    // overridden methods
219
220
    /// @return The size of STP packet
221
    size_t getHeaderLen() const override
222
0
    {
223
0
      return m_DataLen;
224
0
    }
225
226
    /// Does nothing for this layer
227
    void computeCalculateFields() override
228
777
    {}
229
230
    /// @return The OSI layer level of STP (Data Link Layer).
231
    OsiModelLayer getOsiModelLayer() const override
232
777
    {
233
777
      return OsiModelDataLinkLayer;
234
777
    }
235
236
    /// A static method that validates the input data
237
    /// @param[in] data The pointer to the beginning of a byte stream of an Spanning Tree packet
238
    /// @param[in] dataLen The length of the byte stream
239
    /// @return True if the data is valid and can represent an Spanning Tree packet
240
    static bool isDataValid(const uint8_t* data, size_t dataLen);
241
242
    /// A method to create STP layer from existing packet
243
    /// @param[in] data A pointer to the raw data
244
    /// @param[in] dataLen Size of the data in bytes
245
    /// @param[in] prevLayer A pointer to the previous layer
246
    /// @param[in] packet A pointer to the Packet instance where layer will be stored
247
    /// @return A newly allocated STP layer of one of the following types (according to the message type):
248
    /// StpConfigurationBPDULayer, StpTopologyChangeBPDULayer, RapidStpLayer, MultipleStpLayer
249
    static StpLayer* parseStpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
250
  };
251
252
  /// @class StpTopologyChangeBPDULayer
253
  /// Represents network topology change BPDU message of Spanning Tree Protocol
254
  class StpTopologyChangeBPDULayer : public StpLayer
255
  {
256
  protected:
257
0
    explicit StpTopologyChangeBPDULayer(size_t dataLen) : StpLayer(dataLen)
258
0
    {}
259
260
  public:
261
    /// A constructor that creates the layer from an existing packet raw data
262
    /// @param[in] data A pointer to the raw data
263
    /// @param[in] dataLen Size of the data in bytes
264
    /// @param[in] prevLayer A pointer to the previous layer
265
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
266
    StpTopologyChangeBPDULayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
267
4.63k
        : StpLayer(data, dataLen, prevLayer, packet)
268
4.63k
    {}
269
270
    /// Empty c'tor to create a new network topology change (TCN) BPDU layer.
271
    /// Initializes the protocol identifier, version and STP type fields with correct values
272
    StpTopologyChangeBPDULayer();
273
274
    /// Get a pointer to network topology change (TCN) BPDU message
275
    /// @return A pointer to TCN BPDU message
276
    stp_tcn_bpdu* getStpTcnHeader()
277
0
    {
278
0
      return getStpHeader();
279
0
    }
280
281
    // overridden methods
282
283
    /// @return The size of STP TCN message
284
    size_t getHeaderLen() const override
285
267
    {
286
267
      return sizeof(stp_tcn_bpdu);
287
267
    }
288
289
    /// Parses next layer
290
    void parseNextLayer() override;
291
292
    /// @return Returns the protocol info as readable string
293
    std::string toString() const override
294
534
    {
295
534
      return "Spanning Tree Topology Change Notification";
296
534
    }
297
298
    /// A static method that validates the input data
299
    /// @param[in] data The pointer to the beginning of a byte stream of an Spanning Tree Topology Change BPDU
300
    /// packet
301
    /// @param[in] dataLen The length of the byte stream
302
    /// @return True if the data is valid and can represent an Spanning Tree packet
303
    static bool isDataValid(const uint8_t* data, size_t dataLen)
304
1.60k
    {
305
1.60k
      return canReinterpretAs<stp_tcn_bpdu>(data, dataLen);
306
1.60k
    }
307
  };
308
309
  /// @class StpConfigurationBPDULayer
310
  /// Represents configuration BPDU message of Spanning Tree Protocol
311
  class StpConfigurationBPDULayer : public StpTopologyChangeBPDULayer
312
  {
313
  protected:
314
0
    explicit StpConfigurationBPDULayer(size_t dataLen) : StpTopologyChangeBPDULayer(dataLen)
315
0
    {}
316
317
    void serializeLayer(ObjectScope& serializer) const override;
318
319
  public:
320
    /// A constructor that creates the layer from an existing packet raw data
321
    /// @param[in] data A pointer to the raw data
322
    /// @param[in] dataLen Size of the data in bytes
323
    /// @param[in] prevLayer A pointer to the previous layer
324
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
325
    StpConfigurationBPDULayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
326
3.02k
        : StpTopologyChangeBPDULayer(data, dataLen, prevLayer, packet)
327
3.02k
    {}
328
329
    /// @brief Fields describing an STP bridge identifier.
330
    struct BridgeIdSerializedFields
331
    {
332
      /// @return All field descriptors for a bridge identifier
333
      static std::vector<FieldDescriptor> all()
334
0
      {
335
0
        return { Priority, SystemIdExtension, SystemId };
336
0
      }
337
338
      /// @brief Bridge priority, in host byte order.
339
      static const FieldDescriptor Priority;
340
341
      /// @brief System identifier extension, in host byte order.
342
      static const FieldDescriptor SystemIdExtension;
343
344
      /// @brief System identifier as a MAC address string.
345
      static const FieldDescriptor SystemId;
346
    };
347
348
    /// @brief Fields serialized for StpConfigurationBPDULayer, including its base layer fields.
349
    struct SerializedFields : StpLayer::SerializedFields
350
    {
351
      /// @return All field descriptors, including the inherited fields
352
      static std::vector<FieldDescriptor> all()
353
0
      {
354
0
        auto result = StpLayer::SerializedFields::all();
355
0
        std::initializer_list<FieldDescriptor> extra{ Flags,       RootId,     PathCost,   BridgeId,
356
0
                                                    PortId,      MessageAge, MaximumAge, TransmissionInterval,
357
0
                                                    ForwardDelay };
358
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
359
0
        return result;
360
0
      }
361
362
      /// @brief Raw BPDU flag bits.
363
      static const FieldDescriptor Flags;
364
365
      /// @brief Root bridge identifier containing priority, system identifier extension and MAC address.
366
      static const ObjectFieldDescriptor<BridgeIdSerializedFields> RootId;
367
368
      /// @brief Root path cost, in host byte order.
369
      static const FieldDescriptor PathCost;
370
371
      /// @brief Bridge identifier containing priority, system identifier extension and MAC address.
372
      static const ObjectFieldDescriptor<BridgeIdSerializedFields> BridgeId;
373
374
      /// @brief Port identifier, in host byte order.
375
      static const FieldDescriptor PortId;
376
377
      /// @brief BPDU message age, as returned by getMessageAge().
378
      static const FieldDescriptor MessageAge;
379
380
      /// @brief BPDU maximum age, as returned by getMaximumAge().
381
      static const FieldDescriptor MaximumAge;
382
383
      /// @brief BPDU transmission interval, as returned by getTransmissionInterval().
384
      static const FieldDescriptor TransmissionInterval;
385
386
      /// @brief Forward delay, as returned by getForwardDelay().
387
      static const FieldDescriptor ForwardDelay;
388
389
      /// @brief Maximum field ID used by this layer.
390
      static constexpr uint16_t MaxConfigurationFieldID = StpLayer::SerializedFields::MaxStpFieldID + 9;
391
    };
392
393
    /// Empty c'tor to create a new configuration BPDU layer.
394
    /// Initializes the protocol identifier, version and STP type fields with correct values
395
    StpConfigurationBPDULayer();
396
397
    /// Get a pointer to configuration BPDU message
398
    /// @return A pointer to configuration BPDU message
399
    stp_conf_bpdu* getStpConfHeader() const
400
0
    {
401
0
      return reinterpret_cast<stp_conf_bpdu*>(m_Data);
402
0
    }
403
404
    /// Returns the flags of configuration message which indicates purpose of BPDU
405
    /// @return Flags of the configuration message
406
    uint8_t getFlag() const
407
0
    {
408
0
      return getStpConfHeader()->flag;
409
0
    }
410
411
    /// Returns the flags of configuration message which indicates purpose of BPDU
412
    /// @param[in] value Flags of the configuration message
413
    void setFlag(uint8_t value)
414
0
    {
415
0
      getStpConfHeader()->flag = value;
416
0
    }
417
418
    /// Returns the root bridge identifier
419
    /// @return Root bridge identifier
420
    uint64_t getRootId() const;
421
422
    /// Sets the root bridge identifier
423
    /// @param[in] value Root bridge identifier
424
    void setRootId(uint64_t value);
425
426
    /// Returns the priority of root bridge
427
    /// @return Priority of root bridge
428
    uint16_t getRootPriority() const;
429
430
    /// Sets the priority of root bridge
431
    /// @param[in] value Priority of root bridge
432
    void setRootPriority(uint16_t value);
433
434
    /// Returns the system identifier extension of root bridge
435
    /// @return System extension of root bridge
436
    uint16_t getRootSystemIDExtension() const;
437
438
    /// Sets the system identifier extension of root bridge
439
    /// @param[in] value System extension of root bridge
440
    void setRootSystemIDExtension(uint16_t value);
441
442
    /// Returns the system identifier of root bridge
443
    /// @return System identifier of root bridge
444
    pcpp::MacAddress getRootSystemID() const
445
0
    {
446
0
      return IDtoMacAddress(getRootId());
447
0
    }
448
449
    /// Sets the system identifier of root bridge
450
    /// @param[in] value System identifier of root bridge
451
    void setRootSystemID(const pcpp::MacAddress& value);
452
453
    /// Returns the value of the cost of path
454
    /// @return Cost of path
455
    uint32_t getPathCost() const;
456
457
    /// Sets the value of the cost of path
458
    /// @param[in] value Cost of path
459
    void setPathCost(uint32_t value);
460
461
    /// Returns the bridge identifier
462
    /// @return Bridge identifier
463
    uint64_t getBridgeId() const;
464
465
    /// Sets the bridge identifier
466
    /// @param[in] value Bridge identifier
467
    void setBridgeId(uint64_t value);
468
469
    /// Returns the priority of bridge
470
    /// @return Priority of bridge
471
    uint16_t getBridgePriority() const;
472
473
    /// Sets the priority of bridge
474
    /// @param[in] value Priority of bridge
475
    void setBridgePriority(uint16_t value);
476
477
    /// Returns the system identifier extension of bridge
478
    /// @return System extension of bridge
479
    uint16_t getBridgeSystemIDExtension() const;
480
481
    /// Sets the system identifier extension of bridge
482
    /// @param[in] value System extension of bridge
483
    void setBridgeSystemIDExtension(uint16_t value);
484
485
    /// Returns the system identifier of bridge
486
    /// @return System identifier of bridge
487
    pcpp::MacAddress getBridgeSystemID() const
488
0
    {
489
0
      return IDtoMacAddress(getBridgeId());
490
0
    }
491
492
    /// Sets the system identifier of bridge
493
    /// @param[in] value System identifier of bridge
494
    void setBridgeSystemID(const pcpp::MacAddress& value);
495
496
    /// Returns the port identifier
497
    /// @return Port identifier
498
    uint16_t getPortId() const;
499
500
    /// Sets the port identifier
501
    /// @param[in] value Port identifier
502
    void setPortId(uint16_t value);
503
504
    /// Returns age of the BPDU message
505
    /// @return Age of BPDU in seconds
506
    double getMessageAge() const;
507
508
    /// Sets age of the BPDU message
509
    /// @param[in] value Age of BPDU in seconds
510
    void setMessageAge(double value);
511
512
    /// Returns maximum age of the BPDU message
513
    /// @return Maximum age of BPDU in seconds
514
    double getMaximumAge() const;
515
516
    /// Sets maximum age of the BPDU message
517
    /// @param[in] value Maximum age of BPDU in seconds
518
    void setMaximumAge(double value);
519
520
    /// Returns the BPDU transmission interval
521
    /// @return Value of the transmission interval in seconds
522
    double getTransmissionInterval() const;
523
524
    /// Sets the BPDU transmission interval
525
    /// @param[in] value Value of the transmission interval in seconds
526
    void setTransmissionInterval(double value);
527
528
    /// Returns the delay for STP message
529
    /// @return Value of the forward delay in seconds
530
    double getForwardDelay() const;
531
532
    /// Sets the delay for STP message
533
    /// @param[in] value Value of the forward delay in seconds
534
    void setForwardDelay(double value);
535
536
    // overridden methods
537
538
    /// @return The size of STP configuration BPDU message
539
    size_t getHeaderLen() const override
540
314
    {
541
314
      return sizeof(stp_conf_bpdu);
542
314
    }
543
544
    /// Parses next layer
545
    void parseNextLayer() override;
546
547
    /// @return Returns the protocol info as readable string
548
    std::string toString() const override
549
628
    {
550
628
      return "Spanning Tree Configuration";
551
628
    }
552
553
    /// A static method that validates the input data
554
    /// @param[in] data The pointer to the beginning of a byte stream of an Spanning Tree Configuration BPDU packet
555
    /// @param[in] dataLen The length of the byte stream
556
    /// @return True if the data is valid and can represent an Spanning Tree packet
557
    static bool isDataValid(const uint8_t* data, size_t dataLen)
558
1.88k
    {
559
1.88k
      return canReinterpretAs<stp_conf_bpdu>(data, dataLen);
560
1.88k
    }
561
  };
562
563
  /// @class RapidStpLayer
564
  /// Represents Rapid Spanning Tree Protocol (RSTP)
565
  class RapidStpLayer : public StpConfigurationBPDULayer
566
  {
567
  protected:
568
0
    explicit RapidStpLayer(size_t dataLen) : StpConfigurationBPDULayer(dataLen)
569
0
    {}
570
571
    void serializeLayer(ObjectScope& serializer) const override;
572
573
  public:
574
    /// A constructor that creates the layer from an existing packet raw data
575
    /// @param[in] data A pointer to the raw data
576
    /// @param[in] dataLen Size of the data in bytes
577
    /// @param[in] prevLayer A pointer to the previous layer
578
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
579
    RapidStpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
580
1.14k
        : StpConfigurationBPDULayer(data, dataLen, prevLayer, packet)
581
1.14k
    {}
582
583
    /// @brief Fields serialized for RapidStpLayer, including its base layer fields.
584
    struct SerializedFields : StpConfigurationBPDULayer::SerializedFields
585
    {
586
      /// @return All field descriptors, including the inherited fields
587
      static std::vector<FieldDescriptor> all()
588
0
      {
589
0
        auto result = StpConfigurationBPDULayer::SerializedFields::all();
590
0
        std::initializer_list<FieldDescriptor> extra{ Version1Length };
591
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
592
0
        return result;
593
0
      }
594
595
      /// @brief Version 1 length, in bytes.
596
      static const FieldDescriptor Version1Length;
597
598
      /// @brief Maximum field ID used by this layer.
599
      static constexpr uint16_t MaxRapidFieldID =
600
          StpConfigurationBPDULayer::SerializedFields::MaxConfigurationFieldID + 1;
601
    };
602
603
    /// Empty c'tor to create a new Rapid STP layer.
604
    /// Initializes the protocol identifier, version and STP type fields with correct values
605
    RapidStpLayer();
606
607
    /// Get a pointer to Rapid STP header
608
    /// @return A pointer to Rapid STP header
609
    rstp_conf_bpdu* getRstpConfHeader() const
610
0
    {
611
0
      return reinterpret_cast<rstp_conf_bpdu*>(m_Data);
612
0
    }
613
614
    /// Returns the length of version1 field. Fixed at 0x0 for Rapid STP
615
    /// @return Length of the version1 field
616
    uint8_t getVersion1Len() const
617
0
    {
618
0
      return getRstpConfHeader()->version1Len;
619
0
    }
620
621
    /// Returns the length of version1 field
622
    /// @param[in] value Length of the version1 field
623
    void setVersion1Len(uint8_t value)
624
0
    {
625
0
      getRstpConfHeader()->version1Len = value;
626
0
    }
627
628
    // overridden methods
629
630
    /// @return The size of Rapid STP message
631
    size_t getHeaderLen() const override
632
196
    {
633
196
      return sizeof(rstp_conf_bpdu);
634
196
    }
635
636
    /// Parses next layer
637
    void parseNextLayer() override;
638
639
    /// @return Returns the protocol info as readable string
640
    std::string toString() const override
641
360
    {
642
360
      return "Rapid Spanning Tree";
643
360
    }
644
645
    /// A static method that validates the input data
646
    /// @param[in] data The pointer to the beginning of a byte stream of an Rapid STP packet
647
    /// @param[in] dataLen The length of the byte stream
648
    /// @return True if the data is valid and can represent an Spanning Tree packet
649
    static bool isDataValid(const uint8_t* data, size_t dataLen)
650
1.08k
    {
651
1.08k
      return canReinterpretAs<rstp_conf_bpdu>(data, dataLen);
652
1.08k
    }
653
  };
654
655
  /// @class MultipleStpLayer
656
  /// Represents Multiple Spanning Tree Protocol (MSTP). It has limited capabilities (no crafting / limited editing)
657
  /// over MSTI configuration
658
  class MultipleStpLayer : public RapidStpLayer
659
  {
660
  protected:
661
    void serializeLayer(ObjectScope& serializer) const override;
662
663
  public:
664
    /// A constructor that creates the layer from an existing packet raw data
665
    /// @param[in] data A pointer to the raw data
666
    /// @param[in] dataLen Size of the data in bytes
667
    /// @param[in] prevLayer A pointer to the previous layer
668
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
669
    MultipleStpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
670
64
        : RapidStpLayer(data, dataLen, prevLayer, packet)
671
64
    {}
672
673
    /// @brief Fields serialized for MultipleStpLayer, including its base layer fields.
674
    struct SerializedFields : RapidStpLayer::SerializedFields
675
    {
676
      /// @return All field descriptors, including the inherited fields
677
      static std::vector<FieldDescriptor> all()
678
0
      {
679
0
        auto result = RapidStpLayer::SerializedFields::all();
680
0
        std::initializer_list<FieldDescriptor> extra{ Version3Length, ConfigFormatSelector,
681
0
                                                    ConfigName,     ConfigRevision,
682
0
                                                    ConfigDigest,   CistInternalRootPathCost,
683
0
                                                    CistBridgeId,   RemainingHopCount };
684
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
685
0
        return result;
686
0
      }
687
688
      /// @brief Version 3 length, in bytes and host byte order.
689
      static const FieldDescriptor Version3Length;
690
691
      /// @brief MST configuration format selector.
692
      static const FieldDescriptor ConfigFormatSelector;
693
694
      /// @brief MST configuration name, up to 32 characters, terminated at the first null byte.
695
      static const FieldDescriptor ConfigName;
696
697
      /// @brief MST configuration revision, in host byte order.
698
      static const FieldDescriptor ConfigRevision;
699
700
      /// @brief 16-byte MST configuration digest as lowercase hexadecimal without separators.
701
      static const FieldDescriptor ConfigDigest;
702
703
      /// @brief CIST internal root path cost, in host byte order.
704
      static const FieldDescriptor CistInternalRootPathCost;
705
706
      /// @brief CIST bridge identifier containing priority, system identifier extension and MAC address.
707
      static const ObjectFieldDescriptor<BridgeIdSerializedFields> CistBridgeId;
708
709
      /// @brief CIST remaining hop count.
710
      static const FieldDescriptor RemainingHopCount;
711
712
      /// @brief Maximum field ID used by this layer.
713
      static constexpr uint16_t MaxMultipleFieldID = RapidStpLayer::SerializedFields::MaxRapidFieldID + 8;
714
    };
715
716
    /// Empty c'tor to create a new Multiple STP layer.
717
    /// Initializes the protocol identifier, version and STP type fields with correct values
718
    MultipleStpLayer();
719
720
    /// Get a pointer to Multiple STP header
721
    /// @return A pointer to Multiple STP header
722
    mstp_conf_bpdu* getMstpHeader() const
723
0
    {
724
0
      return reinterpret_cast<mstp_conf_bpdu*>(m_Data);
725
0
    }
726
727
    /// @return Length of version3 field
728
    uint16_t getVersion3Len() const;
729
730
    /// Sets the length of version3 field
731
    /// @param[in] value Length of version3 field
732
    void setVersion3Len(uint16_t value);
733
734
    /// Returns the configuration ID format selector
735
    /// @return Configuration ID of format selector
736
    uint8_t getMstConfigurationFormatSelector() const
737
0
    {
738
0
      return getMstpHeader()->mstConfigFormatSelector;
739
0
    }
740
741
    /// Sets the configuration ID format selector
742
    /// @param[in] value Configuration ID of format selector
743
    void setMstConfigurationFormatSelector(uint8_t value)
744
0
    {
745
0
      getMstpHeader()->mstConfigFormatSelector = value;
746
0
    }
747
748
    /// Returns the pointer to configuration name field
749
    /// @return Configuration name
750
    std::string getMstConfigurationName() const;
751
752
    /// Sets the configuration name field
753
    /// @param[in] value Configuration name. Length should be less than 32, if longer value provided first 32
754
    /// characters are used
755
    void setMstConfigurationName(const std::string& value);
756
757
    /// Returns the revision of configuration ID
758
    /// @return Revision of configuration ID
759
    uint16_t getMstConfigRevision() const;
760
761
    /// Sets the revision of configuration ID
762
    /// @param[in] value Revision of configuration ID
763
    void setMstConfigRevision(uint16_t value);
764
765
    /// Returns the pointer to configuration message digest. The field itself always 16 bytes long.
766
    /// @return A pointer to configuration digest
767
    uint8_t* getMstConfigDigest() const
768
0
    {
769
0
      return getMstpHeader()->mstConfigDigest;
770
0
    }
771
772
    /// Sets the pointer to configuration message digest. The field itself always 16 bytes long.
773
    /// @param[in] value Pointer to digest
774
    /// @param[in] len Length of the digest, should be less than 16. If longer first 16 bytes are used
775
    void setMstConfigDigest(const uint8_t* value, uint8_t len);
776
777
    /// Returns CIST internal root path cost
778
    /// @return Value of the internal root path cost
779
    uint32_t getCISTIrpc() const;
780
781
    /// Sets CIST internal root path cost
782
    /// @param[in] value Value of the internal root path cost
783
    void setCISTIrpc(uint32_t value);
784
785
    /// Returns CIST bridge identifier
786
    /// @return Value of the bridge identifier
787
    uint64_t getCISTBridgeId() const;
788
789
    /// Sets CIST bridge identifier
790
    /// @param[in] value Value of the bridge identifier
791
    void setCISTBridgeId(uint64_t value);
792
793
    /// Returns the priority of CIST bridge
794
    /// @return Priority of CIST bridge
795
    uint16_t getCISTBridgePriority() const;
796
797
    /// Sets the priority of CIST bridge
798
    /// @param[in] value Priority of CIST bridge
799
    void setCISTBridgePriority(uint16_t value);
800
801
    /// Returns the system identifier extension of CIST bridge
802
    /// @return System extension of CIST bridge
803
    uint16_t getCISTBridgeSystemIDExtension() const;
804
805
    /// Sets the system identifier extension of CIST bridge
806
    /// @param[in] value System extension of CIST bridge
807
    void setCISTBridgeSystemIDExtension(uint16_t value);
808
809
    /// Returns the system identifier of CIST bridge
810
    /// @return System identifier of CIST bridge
811
    pcpp::MacAddress getCISTBridgeSystemID() const
812
0
    {
813
0
      return IDtoMacAddress(getCISTBridgeId());
814
0
    }
815
816
    /// Sets the system identifier of CIST bridge
817
    /// @param[in] value System identifier of CIST bridge
818
    void setCISTBridgeSystemID(const pcpp::MacAddress& value);
819
820
    /// Returns the remaining hop count
821
    /// @return Value of remaining hop count
822
    uint8_t getRemainingHopCount() const
823
0
    {
824
0
      return getMstpHeader()->remainId;
825
0
    }
826
827
    /// Returns the remaining hop count
828
    /// @param[in] value Value of remaining hop count
829
    void setRemainingHopCount(uint8_t value)
830
0
    {
831
0
      getMstpHeader()->remainId = value;
832
0
    }
833
834
    /// Returns the total number of MSTI configuration messages
835
    /// @return Number of MSTI configuration messages. Can be between 0 and 64.
836
    uint8_t getNumberOfMSTIConfMessages() const
837
0
    {
838
0
      return (getVersion3Len() - (sizeof(mstp_conf_bpdu) - sizeof(rstp_conf_bpdu) - sizeof(uint16_t))) /
839
0
             sizeof(msti_conf_msg);
840
0
    }
841
842
    /// Returns a reference to MSTI configuration messages. An MSTP packet can contain between 0 to 64 MSTI
843
    /// messages. The number of messages can be obtained by using getNumberOfMSTIConfMessages()
844
    /// @return An array pointer to MSTI configuration messages. Returns nullptr if there is no MSTI message.
845
    msti_conf_msg* getMstiConfMessages() const;
846
847
    // overridden methods
848
849
    /// Parses next layer
850
    void parseNextLayer() override
851
64
    {}
852
853
    /// @return Returns the protocol info as readable string
854
    std::string toString() const override
855
32
    {
856
32
      return "Multiple Spanning Tree";
857
32
    }
858
859
    /// A static method that validates the input data
860
    /// @param[in] data The pointer to the beginning of a byte stream of an Multiple STP packet
861
    /// @param[in] dataLen The length of the byte stream
862
    /// @return True if the data is valid and can represent an Spanning Tree packet
863
    static bool isDataValid(const uint8_t* data, size_t dataLen)
864
68
    {
865
68
      return canReinterpretAs<mstp_conf_bpdu>(data, dataLen);
866
68
    }
867
  };
868
}  // namespace pcpp