Coverage Report

Created: 2026-11-12 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/S7CommLayer.cpp
Line
Count
Source
1
0
#define LOG_MODULE PacketLogModuleS7CommLayer
2
3
#include "EndianPortable.h"
4
5
#include "Logger.h"
6
#include "S7CommLayer.h"
7
#include <algorithm>
8
#include <iostream>
9
#include <cstring>
10
#include <sstream>
11
#include <stdexcept>
12
13
namespace pcpp
14
{
15
16
  S7CommLayer::S7CommLayer(uint8_t msgType, uint16_t pduRef, uint16_t paramLength, uint16_t dataLength,
17
                           uint8_t errorClass, uint8_t errorCode)
18
0
  {
19
0
    size_t basicHeaderLen = msgType == 0x03 ? sizeof(s7comm_ack_data_hdr) : sizeof(s7commhdr);
20
0
    size_t headerLen = basicHeaderLen + paramLength + dataLength;
21
0
    allocData(headerLen);
22
23
0
    if (msgType == 0x03)
24
0
    {
25
0
      auto* ack_d = reinterpret_cast<s7comm_ack_data_hdr*>(m_Data);
26
0
      ack_d->protocolId = 0x32;
27
0
      ack_d->msgType = msgType;
28
0
      ack_d->reserved = 0x0000;
29
0
      ack_d->pduRef = htobe16(pduRef);
30
0
      ack_d->paramLength = htobe16(paramLength);
31
0
      ack_d->dataLength = htobe16(dataLength);
32
0
      ack_d->errorClass = errorClass;
33
0
      ack_d->errorCode = errorCode;
34
0
    }
35
0
    else
36
0
    {
37
0
      auto* s7commHdr = reinterpret_cast<s7commhdr*>(m_Data);
38
0
      s7commHdr->protocolId = 0x32;
39
0
      s7commHdr->msgType = msgType;
40
0
      s7commHdr->reserved = 0x0000;
41
0
      s7commHdr->pduRef = htobe16(pduRef);
42
0
      s7commHdr->paramLength = htobe16(paramLength);
43
0
      s7commHdr->dataLength = htobe16(dataLength);
44
0
    }
45
46
0
    m_Parameter = nullptr;
47
0
    m_Protocol = S7COMM;
48
0
  }
49
50
  std::string S7CommLayer::toString() const
51
4.95k
  {
52
4.95k
    std::ostringstream str;
53
4.95k
    str << "S7Comm Layer, ";
54
55
4.95k
    switch (getS7commHeader()->msgType)
56
4.95k
    {
57
1.15k
    case 0x01:
58
1.15k
      str << "Job Request";
59
1.15k
      break;
60
12
    case 0x02:
61
12
      str << "Ack";
62
12
      break;
63
912
    case 0x03:
64
912
      str << "Ack-Data";
65
912
      break;
66
2.05k
    case 0x07:
67
2.05k
      str << "Userdata";
68
2.05k
      break;
69
828
    default:
70
828
      str << "Unknown message";
71
4.95k
    }
72
73
4.95k
    return str.str();
74
4.95k
  }
75
76
  static constexpr const char* msgTypeToString(uint8_t msgType)
77
0
  {
78
0
    switch (msgType)
79
0
    {
80
0
    case 0x01:
81
0
      return "JobRequest";
82
0
    case 0x02:
83
0
      return "Ack";
84
0
    case 0x03:
85
0
      return "AckData";
86
0
    case 0x07:
87
0
      return "Userdata";
88
0
    default:
89
0
      return "Unknown";
90
0
    }
91
0
  }
92
93
  const FieldDescriptor S7CommLayer::SerializedFields::MsgType{ Layer::SerializedFields::MaxID + 1, "msgType" };
94
  const FieldDescriptor S7CommLayer::SerializedFields::MsgTypeName{ Layer::SerializedFields::MaxID + 2,
95
                                                                  "msgTypeName" };
96
  const FieldDescriptor S7CommLayer::SerializedFields::PduRef{ Layer::SerializedFields::MaxID + 3, "pduRef" };
97
  const FieldDescriptor S7CommLayer::SerializedFields::ParamLength{ Layer::SerializedFields::MaxID + 4,
98
                                                                  "paramLength" };
99
  const FieldDescriptor S7CommLayer::SerializedFields::DataLength{ Layer::SerializedFields::MaxID + 5, "dataLength" };
100
  const FieldDescriptor S7CommLayer::SerializedFields::ErrorClass{ Layer::SerializedFields::MaxID + 6, "errorClass" };
101
  const FieldDescriptor S7CommLayer::SerializedFields::ErrorCode{ Layer::SerializedFields::MaxID + 7, "errorCode" };
102
103
  void S7CommLayer::serializeLayer(ObjectScope& serializer) const
104
0
  {
105
0
    serializer.writeField(SerializedFields::MsgType, getMsgType());
106
0
    serializer.writeField(SerializedFields::MsgTypeName, msgTypeToString(getMsgType()));
107
0
    serializer.writeField(SerializedFields::PduRef, getPduRef());
108
0
    serializer.writeField(SerializedFields::ParamLength, getParamLength());
109
0
    serializer.writeField(SerializedFields::DataLength, getDataLength());
110
111
0
    auto* ackDataHeader = getS7commAckDataHeader();
112
0
    if (ackDataHeader != nullptr)
113
0
    {
114
0
      serializer.writeField(SerializedFields::ErrorClass, ackDataHeader->errorClass);
115
0
      serializer.writeField(SerializedFields::ErrorCode, ackDataHeader->errorCode);
116
0
    }
117
0
  }
118
119
  bool S7CommLayer::isDataValid(const uint8_t* data, size_t dataSize)
120
20.2k
  {
121
20.2k
    if (!data || dataSize < sizeof(s7commhdr))
122
464
      return false;
123
124
19.8k
    return data[0] == 0x32;
125
20.2k
  }
126
127
  uint8_t S7CommLayer::getProtocolId() const
128
0
  {
129
0
    return getS7commHeader()->protocolId;
130
0
  }
131
132
  uint8_t S7CommLayer::getMsgType() const
133
0
  {
134
0
    return getS7commHeader()->msgType;
135
0
  }
136
137
  uint16_t S7CommLayer::getParamLength() const
138
0
  {
139
0
    return be16toh(getS7commHeader()->paramLength);
140
0
  }
141
142
  uint16_t S7CommLayer::getPduRef() const
143
0
  {
144
0
    return be16toh(getS7commHeader()->pduRef);
145
0
  }
146
147
  uint16_t S7CommLayer::getDataLength() const
148
0
  {
149
0
    return be16toh(getS7commHeader()->dataLength);
150
0
  }
151
152
  void S7CommLayer::setMsgType(uint8_t msgType) const
153
0
  {
154
0
    getS7commHeader()->msgType = msgType;
155
0
  }
156
157
  uint8_t S7CommLayer::getErrorCode() const
158
0
  {
159
0
    auto* ackDataHeader = getS7commAckDataHeader();
160
0
    if (ackDataHeader == nullptr)
161
0
    {
162
0
      throw std::runtime_error("Error code field not present!");
163
0
    }
164
165
0
    return ackDataHeader->errorCode;
166
0
  }
167
168
  uint8_t S7CommLayer::getErrorClass() const
169
0
  {
170
0
    auto* ackDataHeader = getS7commAckDataHeader();
171
0
    if (ackDataHeader == nullptr)
172
0
    {
173
0
      throw std::runtime_error("Error class field not present!");
174
0
    }
175
176
0
    return ackDataHeader->errorClass;
177
0
  }
178
179
  void S7CommLayer::setPduRef(uint16_t pduRef) const
180
0
  {
181
0
    getS7commHeader()->pduRef = htobe16(pduRef);
182
0
  }
183
184
  void S7CommLayer::setErrorCode(uint8_t errorCode) const
185
0
  {
186
0
    auto* ackDataHeader = getS7commAckDataHeader();
187
0
    if (ackDataHeader == nullptr)
188
0
    {
189
0
      PCPP_LOG_ERROR("Cannot set the error code, the layer has no Ack-Data header");
190
0
      return;
191
0
    }
192
193
0
    ackDataHeader->errorCode = errorCode;
194
0
  }
195
196
  void S7CommLayer::setErrorClass(uint8_t errorClass) const
197
0
  {
198
0
    auto* ackDataHeader = getS7commAckDataHeader();
199
0
    if (ackDataHeader == nullptr)
200
0
    {
201
0
      PCPP_LOG_ERROR("Cannot set the error class, the layer has no Ack-Data header");
202
0
      return;
203
0
    }
204
205
0
    ackDataHeader->errorClass = errorClass;
206
0
  }
207
208
  const S7CommParameter* S7CommLayer::getParameter()
209
0
  {
210
0
    if (!m_Parameter)
211
0
    {
212
      // the parameter length comes from the packet, so keep it inside the layer
213
0
      size_t offset = std::min(getS7commHeaderLength(), m_DataLen);
214
0
      size_t paramLength = std::min(static_cast<size_t>(getParamLength()), m_DataLen - offset);
215
0
      m_Parameter = std::unique_ptr<S7CommParameter>(new S7CommParameter(m_Data + offset, paramLength));
216
0
    }
217
218
0
    return m_Parameter.get();
219
0
  }
220
221
  size_t S7CommLayer::getS7commHeaderLength() const
222
0
  {
223
0
    if (getS7commHeader()->msgType == 0x03)
224
0
    {
225
0
      return sizeof(s7comm_ack_data_hdr);
226
0
    }
227
0
    return sizeof(s7commhdr);
228
0
  }
229
230
}  // namespace pcpp