Coverage Report

Created: 2026-11-12 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/header/S7CommLayer.h
Line
Count
Source
1
#pragma once
2
3
#include <memory>
4
#include "EthLayer.h"
5
#include "Layer.h"
6
7
/// @namespace pcpp
8
/// @brief The main namespace for the PcapPlusPlus lib
9
namespace pcpp
10
{
11
  /// @struct s7commhdr
12
  /// Represents a S7COMM protocol header
13
#pragma pack(push, 1)
14
  typedef struct
15
  {
16
    /// protocol id
17
    uint8_t protocolId;
18
    /// message type
19
    uint8_t msgType;
20
    /// redundancy identification (reserved)
21
    uint16_t reserved;
22
    /// protocol data unit reference
23
    uint16_t pduRef;
24
    /// parameter length
25
    uint16_t paramLength;
26
    /// data length
27
    uint16_t dataLength;
28
  } s7commhdr;
29
#pragma pack(pop)
30
  static_assert(sizeof(s7commhdr) == 10, "s7commhdr size is not 10 bytes");
31
32
  /// @struct s7comm_ack_data_hdr
33
  /// Represents a S7COMM protocol header with Ack-Data header
34
#pragma pack(push, 1)
35
  struct s7comm_ack_data_hdr : s7commhdr
36
  {
37
    /// error class
38
    uint8_t errorClass;
39
    /// error code
40
    uint8_t errorCode;
41
  };
42
#pragma pack(pop)
43
  static_assert(sizeof(s7comm_ack_data_hdr) == 12, "s7comm_ack_data_hdr size is not 12 bytes");
44
45
  /// @class S7CommParameter
46
  /// Represents a S7COMM (S7 Communication) protocol Parameter
47
  class S7CommParameter
48
  {
49
    friend class S7CommLayer;
50
51
  public:
52
    S7CommParameter()
53
0
    {}
54
55
0
    virtual ~S7CommParameter() = default;
56
57
    /// @return The data of the Parameter
58
    uint8_t* getData() const
59
0
    {
60
0
      return m_Data;
61
0
    }
62
    /// @return The length of the Parameter data
63
    size_t getDataLength() const
64
0
    {
65
0
      return m_DataLen;
66
0
    }
67
68
  private:
69
0
    S7CommParameter(uint8_t* data, size_t dataLen) : m_Data(data), m_DataLen(dataLen)
70
0
    {}
71
    uint8_t* m_Data;
72
    size_t m_DataLen;
73
  };
74
  /// @class S7CommLayer
75
  /// Represents a S7COMM (S7 Communication) protocol
76
  class S7CommLayer : public Layer
77
  {
78
  public:
79
    /// A constructor that allocates a new S7comm header
80
    /// @param[in] msgType The general type of the message
81
    /// @param[in] pduRef Link responses to their requests
82
    /// @param[in] paramLength The length of the parameter field
83
    /// @param[in] dataLength The length of the data field
84
    /// @param[in] errorClass The value of the error class
85
    /// @param[in] errorCode The value of the error code
86
    S7CommLayer(uint8_t msgType, uint16_t pduRef, uint16_t paramLength, uint16_t dataLength, uint8_t errorClass = 0,
87
                uint8_t errorCode = 0);
88
89
    /// A constructor that creates the layer from an existing packet raw data
90
    /// @param[in] data A pointer to the raw data (will be casted to @ref s7commhdr)
91
    /// @param[in] dataLen Size of the data in bytes
92
    /// @param[in] prevLayer A pointer to the previous layer
93
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
94
    S7CommLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
95
17.7k
        : Layer(data, dataLen, prevLayer, packet, S7COMM)
96
17.7k
    {}
97
98
17.7k
    ~S7CommLayer() override = default;
99
100
    /// @return S7comm protocol id
101
    uint8_t getProtocolId() const;
102
103
    /// @return S7comm message type
104
    uint8_t getMsgType() const;
105
106
    /// @return S7comm PDU ref
107
    uint16_t getPduRef() const;
108
109
    /// @return S7comm parameter length
110
    uint16_t getParamLength() const;
111
112
    /// @return S7comm data length
113
    uint16_t getDataLength() const;
114
115
    /// @return S7comm error code
116
    /// @throw std::runtime_error if the message is not Ack-Data (message type 0x03) or is too short to hold the
117
    /// error code
118
    uint8_t getErrorCode() const;
119
120
    /// @return S7comm error class
121
    /// @throw std::runtime_error if the message is not Ack-Data (message type 0x03) or is too short to hold the
122
    /// error class
123
    uint8_t getErrorClass() const;
124
125
    /// @return S7comm parameter
126
    const S7CommParameter* getParameter();
127
128
    /// Set the value of the message type
129
    /// @param[in] msgType The value of the message type
130
    void setMsgType(uint8_t msgType) const;
131
132
    /// Set the value of the PDU ref
133
    /// @param[in] pduRef The value of the PDU ref
134
    void setPduRef(uint16_t pduRef) const;
135
136
    /// Set the value of the error code
137
    /// @param[in] errorCode The value of the error code
138
    void setErrorCode(uint8_t errorCode) const;
139
    /// Set the value of the error class
140
    /// @param[in] errorClass The value of the error class
141
    void setErrorClass(uint8_t errorClass) const;
142
143
    /// @return Size of S7CommLayer
144
    size_t getHeaderLen() const override
145
2.47k
    {
146
2.47k
      return m_DataLen;
147
2.47k
    }
148
149
    /// Does nothing for this layer (S7CommLayer is always last)
150
    void computeCalculateFields() override
151
2.47k
    {}
152
153
    /// Does nothing for this layer (S7CommLayer is always last)
154
    void parseNextLayer() override
155
17.7k
    {}
156
157
    /// A static method that takes a byte array and detects whether it is a S7COMM
158
    /// @param[in] data A byte array
159
    /// @param[in] dataSize The byte array size (in bytes)
160
    /// @return True if the data looks like a valid S7COMM layer
161
    static bool isDataValid(const uint8_t* data, size_t dataSize);
162
163
    std::string toString() const override;
164
165
    OsiModelLayer getOsiModelLayer() const override
166
2.47k
    {
167
2.47k
      return OsiModelApplicationLayer;
168
2.47k
    }
169
170
    /// @struct SerializedFields
171
    /// Fields written by S7CommLayer's serializeLayer(), in addition to
172
    /// Layer::SerializedFields.
173
    struct SerializedFields : Layer::SerializedFields
174
    {
175
      /// @return All field descriptors for S7CommLayer
176
      static std::vector<FieldDescriptor> all()
177
0
      {
178
0
        auto result = Layer::SerializedFields::all();
179
0
        std::initializer_list<FieldDescriptor> extra{ MsgType,    MsgTypeName, PduRef,   ParamLength,
180
0
                                                    DataLength, ErrorClass,  ErrorCode };
181
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
182
0
        return result;
183
0
      }
184
185
      /// @brief Field descriptor for the S7COMM message type, written as a number.
186
      static const FieldDescriptor MsgType;
187
188
      /// @brief Field descriptor for the S7COMM message type name, written as a string.
189
      static const FieldDescriptor MsgTypeName;
190
191
      /// @brief Field descriptor for the protocol data unit reference, written as a number.
192
      static const FieldDescriptor PduRef;
193
194
      /// @brief Field descriptor for the parameter length (in bytes), written as a number.
195
      static const FieldDescriptor ParamLength;
196
197
      /// @brief Field descriptor for the data length (in bytes), written as a number.
198
      static const FieldDescriptor DataLength;
199
200
      /// @brief Field descriptor for the error class, written as a number. Only written for Ack-Data messages
201
      /// (message type 0x03).
202
      static const FieldDescriptor ErrorClass;
203
204
      /// @brief Field descriptor for the error code, written as a number. Only written for Ack-Data messages
205
      /// (message type 0x03).
206
      static const FieldDescriptor ErrorCode;
207
    };
208
209
  protected:
210
    void serializeLayer(ObjectScope& serializer) const override;
211
212
  private:
213
    s7commhdr* getS7commHeader() const
214
4.95k
    {
215
4.95k
      return reinterpret_cast<s7commhdr*>(m_Data);
216
4.95k
    }
217
218
    s7comm_ack_data_hdr* getS7commAckDataHeader() const
219
0
    {
220
0
      if (getS7commHeader()->msgType == 0x03 && m_DataLen >= sizeof(s7comm_ack_data_hdr))
221
0
      {
222
0
        return reinterpret_cast<s7comm_ack_data_hdr*>(m_Data);
223
0
      }
224
0
      return nullptr;
225
0
    }
226
227
    size_t getS7commHeaderLength() const;
228
229
    std::unique_ptr<S7CommParameter> m_Parameter;
230
  };
231
232
}  // namespace pcpp