Coverage Report

Created: 2026-05-30 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/StpLayer.cpp
Line
Count
Source
1
0
#define LOG_MODULE PacketLogModuleStpLayer
2
3
#include "StpLayer.h"
4
#include "PayloadLayer.h"
5
#include "EndianPortable.h"
6
#include "Logger.h"
7
8
namespace pcpp
9
{
10
11
  // ---------------------- Class STPLayer ----------------------
12
  MacAddress StpLayer::StpMulticastDstMAC("01:80:C2:00:00:00");
13
  MacAddress StpLayer::StpUplinkFastMulticastDstMAC("01:00:0C:CD:CD:CD");
14
15
  MacAddress StpLayer::IDtoMacAddress(uint64_t id)
16
0
  {
17
0
    return MacAddress((id >> 40) & 0xFF, (id >> 32) & 0xFF, (id >> 24) & 0xFF, (id >> 16) & 0xFF, (id >> 8) & 0xFF,
18
0
                      id & 0xFF);
19
0
  }
20
21
  uint64_t StpLayer::macAddressToID(const pcpp::MacAddress& addr)
22
0
  {
23
0
    uint8_t value[6] = { 0 };
24
0
    addr.copyTo(value);
25
0
    return ((uint64_t(value[0]) << 40) | (uint64_t(value[1]) << 32) | (uint64_t(value[2]) << 24) |
26
0
            (uint64_t(value[3]) << 16) | (uint64_t(value[4]) << 8) | (uint64_t(value[5])));
27
0
  }
28
29
  bool StpLayer::isDataValid(const uint8_t* data, size_t dataLen)
30
0
  {
31
0
    return data && dataLen;
32
0
  }
33
34
  StpLayer* StpLayer::parseStpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
35
0
  {
36
0
    if (dataLen >= sizeof(stp_tcn_bpdu))
37
0
    {
38
0
      stp_tcn_bpdu* ptr = reinterpret_cast<stp_tcn_bpdu*>(data);
39
0
      switch (ptr->type)
40
0
      {
41
0
      case 0x00:
42
0
        return StpConfigurationBPDULayer::isDataValid(data, dataLen)
43
0
                   ? new StpConfigurationBPDULayer(data, dataLen, prevLayer, packet)
44
0
                   : nullptr;
45
0
      case 0x02:
46
0
        if (ptr->version == 0x2)
47
0
          return RapidStpLayer::isDataValid(data, dataLen)
48
0
                     ? new RapidStpLayer(data, dataLen, prevLayer, packet)
49
0
                     : nullptr;
50
0
        if (ptr->version == 0x3)
51
0
          return MultipleStpLayer::isDataValid(data, dataLen)
52
0
                     ? new MultipleStpLayer(data, dataLen, prevLayer, packet)
53
0
                     : nullptr;
54
0
        PCPP_LOG_DEBUG("Unknown Spanning Tree Version");
55
0
        return nullptr;
56
0
      case 0x80:
57
0
        return StpTopologyChangeBPDULayer::isDataValid(data, dataLen)
58
0
                   ? new StpTopologyChangeBPDULayer(data, dataLen, prevLayer, packet)
59
0
                   : nullptr;
60
      // TODO: Per VLAN Spanning Tree+ (PVST+)
61
      // TODO: Rapid Per VLAN Spanning Tree+ (RPVST+)
62
      // TODO: Cisco Uplink Fast
63
0
      default:
64
0
        PCPP_LOG_DEBUG("Unknown Spanning Tree Protocol type");
65
0
        return nullptr;
66
0
      }
67
0
    }
68
69
0
    PCPP_LOG_DEBUG("Data length is less than any STP header");
70
0
    return nullptr;
71
0
  }
72
73
  // ---------------------- Class StpTopologyChangeBPDULayer ----------------------
74
0
  StpTopologyChangeBPDULayer::StpTopologyChangeBPDULayer() : StpLayer(sizeof(stp_tcn_bpdu))
75
0
  {
76
    // Set initial values for TCN
77
0
    setProtoId(0x0);
78
0
    setVersion(0x0);
79
0
    setType(0x80);
80
0
  }
81
82
  void StpTopologyChangeBPDULayer::parseNextLayer()
83
0
  {
84
0
    if (m_DataLen > sizeof(stp_tcn_bpdu))
85
0
    {
86
0
      constructNextLayer<PayloadLayer>(m_Data, m_DataLen - sizeof(stp_tcn_bpdu));
87
0
    }
88
0
  }
89
90
  // ---------------------- Class StpConfigurationBPDULayer ----------------------
91
0
  StpConfigurationBPDULayer::StpConfigurationBPDULayer() : StpTopologyChangeBPDULayer(sizeof(stp_conf_bpdu))
92
0
  {
93
    // Set initial value for configuration BPDU
94
0
    setProtoId(0x0);
95
0
    setVersion(0x0);
96
0
    setType(0x0);
97
0
  }
98
99
  uint64_t StpConfigurationBPDULayer::getRootId() const
100
0
  {
101
0
    return be64toh(getStpConfHeader()->rootId);
102
0
  }
103
104
  void StpConfigurationBPDULayer::setRootId(uint64_t value)
105
0
  {
106
0
    getStpConfHeader()->rootId = htobe64(value);
107
0
  }
108
109
  uint16_t StpConfigurationBPDULayer::getRootPriority() const
110
0
  {
111
0
    return be16toh(getStpConfHeader()->rootId) & 0xf000;
112
0
  }
113
114
  void StpConfigurationBPDULayer::setRootPriority(uint16_t value)
115
0
  {
116
0
    getStpConfHeader()->rootId = (getStpConfHeader()->rootId & ~htobe16(0xf000)) | htobe16(value & 0xf000);
117
0
  }
118
119
  uint16_t StpConfigurationBPDULayer::getRootSystemIDExtension() const
120
0
  {
121
0
    return be16toh(getStpConfHeader()->rootId) & 0x0fff;
122
0
  }
123
124
  void StpConfigurationBPDULayer::setRootSystemIDExtension(uint16_t value)
125
0
  {
126
0
    getStpConfHeader()->rootId = (getStpConfHeader()->rootId & ~htobe16(0x0fff)) | htobe16(value & 0x0fff);
127
0
  }
128
129
  void StpConfigurationBPDULayer::setRootSystemID(const pcpp::MacAddress& value)
130
0
  {
131
0
    setRootId((getRootId() & (uint64_t(0xffff) << 48)) | macAddressToID(value));
132
0
  };
133
134
  uint32_t StpConfigurationBPDULayer::getPathCost() const
135
0
  {
136
0
    return be32toh(getStpConfHeader()->pathCost);
137
0
  }
138
139
  void StpConfigurationBPDULayer::setPathCost(uint32_t value)
140
0
  {
141
0
    getStpConfHeader()->pathCost = htobe32(value);
142
0
  }
143
144
  uint64_t StpConfigurationBPDULayer::getBridgeId() const
145
0
  {
146
0
    return be64toh(getStpConfHeader()->bridgeId);
147
0
  }
148
149
  void StpConfigurationBPDULayer::setBridgeId(uint64_t value)
150
0
  {
151
0
    getStpConfHeader()->bridgeId = htobe64(value);
152
0
  }
153
154
  uint16_t StpConfigurationBPDULayer::getBridgePriority() const
155
0
  {
156
0
    return be16toh(getStpConfHeader()->bridgeId) & 0xf000;
157
0
  }
158
159
  void StpConfigurationBPDULayer::setBridgePriority(uint16_t value)
160
0
  {
161
0
    getStpConfHeader()->bridgeId = (getStpConfHeader()->bridgeId & ~htobe16(0xf000)) | htobe16(value & 0xf000);
162
0
  }
163
164
  uint16_t StpConfigurationBPDULayer::getBridgeSystemIDExtension() const
165
0
  {
166
0
    return be16toh(getStpConfHeader()->bridgeId) & 0x0fff;
167
0
  }
168
169
  void StpConfigurationBPDULayer::setBridgeSystemIDExtension(uint16_t value)
170
0
  {
171
0
    getStpConfHeader()->bridgeId = (getStpConfHeader()->bridgeId & ~htobe16(0x0fff)) | htobe16(value & 0x0fff);
172
0
  }
173
174
  void StpConfigurationBPDULayer::setBridgeSystemID(const pcpp::MacAddress& value)
175
0
  {
176
0
    setBridgeId((getBridgeId() & (uint64_t(0xffff) << 48)) | macAddressToID(value));
177
0
  }
178
179
  uint16_t StpConfigurationBPDULayer::getPortId() const
180
0
  {
181
0
    return be16toh(getStpConfHeader()->portId);
182
0
  }
183
184
  void StpConfigurationBPDULayer::setPortId(uint16_t value)
185
0
  {
186
0
    getStpConfHeader()->portId = htobe16(value);
187
0
  }
188
189
  double StpConfigurationBPDULayer::getMessageAge() const
190
0
  {
191
0
    return getStpConfHeader()->msgAge;
192
0
  }
193
194
  void StpConfigurationBPDULayer::setMessageAge(double value)
195
0
  {
196
0
    getStpConfHeader()->msgAge = value;
197
0
  }
198
199
  double StpConfigurationBPDULayer::getMaximumAge() const
200
0
  {
201
0
    return getStpConfHeader()->maxAge;
202
0
  }
203
204
  void StpConfigurationBPDULayer::setMaximumAge(double value)
205
0
  {
206
0
    getStpConfHeader()->maxAge = value;
207
0
  }
208
209
  double StpConfigurationBPDULayer::getTransmissionInterval() const
210
0
  {
211
0
    return getStpConfHeader()->helloTime;
212
0
  }
213
214
  void StpConfigurationBPDULayer::setTransmissionInterval(double value)
215
0
  {
216
0
    getStpConfHeader()->helloTime = value;
217
0
  }
218
219
  double StpConfigurationBPDULayer::getForwardDelay() const
220
0
  {
221
0
    return getStpConfHeader()->forwardDelay;
222
0
  }
223
224
  void StpConfigurationBPDULayer::setForwardDelay(double value)
225
0
  {
226
0
    getStpConfHeader()->forwardDelay = value;
227
0
  }
228
229
  void StpConfigurationBPDULayer::parseNextLayer()
230
0
  {
231
0
    if (m_DataLen > sizeof(stp_conf_bpdu))
232
0
    {
233
0
      constructNextLayer<PayloadLayer>(m_Data, m_DataLen - sizeof(stp_conf_bpdu));
234
0
    }
235
0
  }
236
237
  // ---------------------- Class RapidStpLayer ----------------------
238
0
  RapidStpLayer::RapidStpLayer() : StpConfigurationBPDULayer(sizeof(rstp_conf_bpdu))
239
0
  {
240
    // Set initial value for Rapid STP
241
0
    setProtoId(0x0);
242
0
    setVersion(0x2);
243
0
    setType(0x2);
244
0
  }
245
246
  void RapidStpLayer::parseNextLayer()
247
0
  {
248
0
    if (m_DataLen > sizeof(rstp_conf_bpdu))
249
0
    {
250
0
      constructNextLayer<PayloadLayer>(m_Data, m_DataLen - sizeof(rstp_conf_bpdu));
251
0
    }
252
0
  }
253
254
  // ---------------------- Class MultipleStpLayer ----------------------
255
0
  MultipleStpLayer::MultipleStpLayer() : RapidStpLayer(sizeof(mstp_conf_bpdu))
256
0
  {
257
    // Set initial value for Multiple STP
258
0
    setProtoId(0x0);
259
0
    setVersion(0x3);
260
0
    setType(0x2);
261
0
  }
262
263
  uint16_t MultipleStpLayer::getVersion3Len() const
264
0
  {
265
0
    return be16toh(getMstpHeader()->version3Len);
266
0
  }
267
268
  void MultipleStpLayer::setVersion3Len(uint16_t value)
269
0
  {
270
0
    getMstpHeader()->version3Len = htobe16(value);
271
0
  }
272
273
  uint32_t MultipleStpLayer::getCISTIrpc() const
274
0
  {
275
0
    return be32toh(getMstpHeader()->irpc);
276
0
  }
277
278
  void MultipleStpLayer::setCISTIrpc(uint32_t value)
279
0
  {
280
0
    getMstpHeader()->irpc = htobe32(value);
281
0
  }
282
283
  uint64_t MultipleStpLayer::getCISTBridgeId() const
284
0
  {
285
0
    return be64toh(getMstpHeader()->cistBridgeId);
286
0
  }
287
288
  void MultipleStpLayer::setCISTBridgeId(uint64_t value)
289
0
  {
290
0
    getMstpHeader()->cistBridgeId = htobe64(value);
291
0
  }
292
293
  uint16_t MultipleStpLayer::getCISTBridgePriority() const
294
0
  {
295
0
    return be16toh(getMstpHeader()->cistBridgeId) & 0xf000;
296
0
  }
297
298
  void MultipleStpLayer::setCISTBridgePriority(uint16_t value)
299
0
  {
300
0
    getMstpHeader()->cistBridgeId = (getMstpHeader()->cistBridgeId & ~htobe16(0xf000)) | htobe16(value & 0xf000);
301
0
  }
302
303
  uint16_t MultipleStpLayer::getCISTBridgeSystemIDExtension() const
304
0
  {
305
0
    return be16toh(getMstpHeader()->cistBridgeId) & 0x0fff;
306
0
  }
307
308
  void MultipleStpLayer::setCISTBridgeSystemIDExtension(uint16_t value)
309
0
  {
310
0
    getMstpHeader()->cistBridgeId = (getMstpHeader()->cistBridgeId & ~htobe16(0x0fff)) | htobe16(value & 0x0fff);
311
0
  }
312
313
  void MultipleStpLayer::setCISTBridgeSystemID(const pcpp::MacAddress& value)
314
0
  {
315
0
    setCISTBridgeId((getCISTBridgeId() & (uint64_t(0xffff) << 48)) | macAddressToID(value));
316
0
  }
317
318
  std::string MultipleStpLayer::getMstConfigurationName() const
319
0
  {
320
0
    std::string str = std::string(reinterpret_cast<char*>(getMstpHeader()->mstConfigName), 32);
321
0
    str.erase(std::find(str.begin(), str.end(), '\0'), str.end());
322
0
    return str;
323
0
  }
324
325
  uint16_t MultipleStpLayer::getMstConfigRevision() const
326
0
  {
327
0
    return be16toh(getMstpHeader()->mstConfigRevision);
328
0
  }
329
330
  void MultipleStpLayer::setMstConfigRevision(uint16_t value)
331
0
  {
332
0
    getMstpHeader()->mstConfigRevision = htobe16(value);
333
0
  }
334
335
  void MultipleStpLayer::setMstConfigDigest(const uint8_t* value, uint8_t len)
336
0
  {
337
0
    memset(getMstpHeader()->mstConfigDigest, 0, 16);
338
0
    memcpy(getMstpHeader()->mstConfigDigest, value, std::min<size_t>(len, 16));
339
0
  }
340
341
  void MultipleStpLayer::setMstConfigurationName(const std::string& value)
342
0
  {
343
0
    memset(getMstpHeader()->mstConfigName, 0, 32);
344
0
    memcpy(getMstpHeader()->mstConfigName, value.c_str(), std::min<size_t>(value.size(), 32));
345
0
  }
346
347
  msti_conf_msg* MultipleStpLayer::getMstiConfMessages() const
348
0
  {
349
0
    if (getNumberOfMSTIConfMessages())
350
0
      return reinterpret_cast<msti_conf_msg*>(m_Data + sizeof(mstp_conf_bpdu));
351
0
    return nullptr;
352
0
  }
353
354
}  // namespace pcpp