Coverage Report

Created: 2026-11-12 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/header/SomeIpLayer.h
Line
Count
Source
1
#pragma once
2
3
#include "Layer.h"
4
#include <unordered_set>
5
6
/// @file
7
8
/// @namespace pcpp
9
/// @brief The main namespace for the PcapPlusPlus lib
10
namespace pcpp
11
{
12
  /// @class SomeIpLayer
13
  /// Represents a SOME/IP protocol layer
14
  class SomeIpLayer : public Layer
15
  {
16
  public:
17
    /// SOME/IP message types
18
    enum class MsgType : uint8_t
19
    {
20
      /// A request expecting a response (even void)
21
      REQUEST = 0x00,
22
      /// Acknowledgment for REQUEST(optional)
23
      REQUEST_ACK = 0x40,
24
      /// A fire&forget request
25
      REQUEST_NO_RETURN = 0x01,
26
      /// Acknowledgment for REQUEST_NO_RETURN(informational)
27
      REQUEST_NO_RETURN_ACK = 0x41,
28
      /// A request of a notification expecting no response
29
      NOTIFICATION = 0x02,
30
      /// Acknowledgment for NOTIFICATION(informational)
31
      NOTIFICATION_ACK = 0x42,
32
      /// The response message
33
      RESPONSE = 0x80,
34
      /// The Acknowledgment for RESPONSE(informational)
35
      RESPONSE_ACK = 0xC0,
36
      /// The response containing an error
37
      ERRORS = 0x81,
38
      /// Acknowledgment for ERROR(informational)
39
      ERROR_ACK = 0xC1,
40
      /// A TP request expecting a response (even void)
41
      TP_REQUEST = 0x20,
42
      /// A TP fire&forget request
43
      TP_REQUEST_NO_RETURN = 0x21,
44
      /// A TP request of a notification/event callback expecting no response
45
      TP_NOTIFICATION = 0x22,
46
      /// The TP response message
47
      TP_RESPONSE = 0xa0,
48
      /// The TP response containing an error
49
      TP_ERROR = 0xa1,
50
    };
51
52
    /// @struct someiphdr
53
    /// Represents a SOME/IP protocol header
54
#pragma pack(push, 1)
55
    struct someiphdr
56
    {
57
      /// Service ID
58
      uint16_t serviceID;
59
      /// Method ID. Most significant bit 0 when E2E communication. 1 when SOME/IP event
60
      uint16_t methodID;
61
      /// Length. Also covers payload. Excludes serviceID, methodID and length field itself
62
      uint32_t length;
63
      /// Client ID
64
      uint16_t clientID;
65
      /// Session ID
66
      uint16_t sessionID;
67
      /// Protocol Version
68
      uint8_t protocolVersion;
69
      /// Interface Version
70
      uint8_t interfaceVersion;
71
      /// Message Type
72
      uint8_t msgType;
73
      /// Return Code
74
      uint8_t returnCode;
75
    };
76
#pragma pack(pop)
77
    static_assert(sizeof(someiphdr) == 16, "someiphdr size is not 16 bytes");
78
79
    /// A constructor that creates the layer from an existing packet raw data
80
    /// @param[in] data A pointer to the raw data (will be casted to someiphdr)
81
    /// @param[in] dataLen Size of the data in bytes
82
    /// @param[in] prevLayer A pointer to the previous layer
83
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
84
    SomeIpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
85
48.9k
        : Layer(data, dataLen, prevLayer, packet, SomeIP)
86
48.9k
    {}
87
88
    /// Construct a new layer object
89
    /// @param[in] serviceID Service ID
90
    /// @param[in] methodID Method ID
91
    /// @param[in] clientID Client ID
92
    /// @param[in] sessionID Session ID
93
    /// @param[in] interfaceVersion Interface Version
94
    /// @param[in] type Type of the message
95
    /// @param[in] returnCode Return Code
96
    /// @param[in] data A pointer to the raw data
97
    /// @param[in] dataLen Size of the data in bytes
98
    /// holds the reference to a data buffer. This option can be used to reduce the number of copies to generate
99
    /// packets.
100
    SomeIpLayer(uint16_t serviceID, uint16_t methodID, uint16_t clientID, uint16_t sessionID,
101
                uint8_t interfaceVersion, MsgType type, uint8_t returnCode, const uint8_t* const data = nullptr,
102
                size_t dataLen = 0);
103
104
    /// Destroy the layer object
105
    ~SomeIpLayer() override = default;
106
107
    /// A static method that creates a SOME/IP or SOME/IP-TP layer from packet raw data. Returns PayloadLayer if
108
    /// data is not valid.
109
    /// @param[in] data A pointer to the raw data
110
    /// @param[in] dataLen Size of the data in bytes
111
    /// @param[in] prevLayer A pointer to the previous layer
112
    /// @param[in] packet A pointer to the Packet instance where layer will be stored
113
    /// @return Layer* A newly allocated layer
114
    static Layer* parseSomeIpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
115
116
    /// Get a pointer to the basic SOME/IP header. Notice this points directly to the data, so every change will
117
    /// change the actual packet data
118
    /// @return A pointer to the someiphdr
119
    someiphdr* getSomeIpHeader() const
120
73.4k
    {
121
73.4k
      return reinterpret_cast<someiphdr*>(m_Data);
122
73.4k
    }
123
124
    /// Checks if given port is a SOME/IP protocol port (only Service Discovery ports are checked for now)
125
    /// @param[in] port Port to check
126
    /// @return true if SOME/IP protocol port, false if not
127
    static bool isSomeIpPort(uint16_t port);
128
129
    /// Adds port to a list of ports where pcap checks for SOME/IP communication.
130
    /// Each port must be removed at the end in order to have no memory leak.
131
    /// @param[in] port Port to add
132
    static void addSomeIpPort(uint16_t port);
133
134
    /// Removes port from a list of ports where pcap checks for SOME/IP communication.
135
    /// @param[in] port Port to remove
136
    static void removeSomeIpPort(uint16_t port);
137
138
    /// Removes all ports from a list of ports where pcap checks for SOME/IP communication.
139
    static void removeAllSomeIpPorts();
140
141
    /// Get the messageID
142
    /// @return uint32_t returned in host endian
143
    uint32_t getMessageID() const;
144
145
    /// Set the Message ID
146
    /// @param[in] messageID messageID to set
147
    void setMessageID(uint32_t messageID);
148
149
    /// Get the serviceID
150
    /// @return uint16_t returned in host endian
151
    uint16_t getServiceID() const;
152
153
    /// Set the Service ID
154
    /// @param[in] serviceID serviceID to set
155
    void setServiceID(uint16_t serviceID);
156
157
    /// Get the methodID
158
    /// @return uint16_t returned in host endian
159
    uint16_t getMethodID() const;
160
161
    /// Set the Method ID
162
    /// @param[in] methodID methodID to set
163
    void setMethodID(uint16_t methodID);
164
165
    /// Get the Length Field of the SOME/IP header
166
    /// @return uint32_t The length field of the SOME/IP header
167
    uint32_t getLengthField() const;
168
169
    /// Get the requestID
170
    /// @return uint32_t returned in host endian
171
    uint32_t getRequestID() const;
172
173
    /// Set the Request ID
174
    /// @param[in] requestID requestID to set
175
    void setRequestID(uint32_t requestID);
176
177
    /// Get the sessionID
178
    /// @return uint16_t returned in host endian
179
    uint16_t getSessionID() const;
180
181
    /// Set the Session ID
182
    /// @param[in] sessionID sessionID to set
183
    void setSessionID(uint16_t sessionID);
184
185
    /// Get the clientID
186
    /// @return uint16_t returned in host endian
187
    uint16_t getClientID() const;
188
189
    /// Set the Client ID
190
    /// @param[in] clientID clientID to set
191
    void setClientID(uint16_t clientID);
192
193
    /// Get the protocolVersion
194
    /// @return uint8_t
195
    uint8_t getProtocolVersion() const;
196
197
    /// Set the Protocol Version
198
    /// @param[in] version version to set
199
    void setProtocolVersion(uint8_t version);
200
201
    /// Get the interfaceVersion
202
    /// @return uint8_t
203
    uint8_t getInterfaceVersion() const;
204
205
    /// Set the Interface Version
206
    /// @param[in] version version to set
207
    void setInterfaceVersion(uint8_t version);
208
209
    /// Get the message type
210
    /// @return uint8_t
211
    uint8_t getMessageTypeAsInt() const;
212
213
    /// Get the message type
214
    /// @return SomeIpLayer::MsgType
215
    SomeIpLayer::MsgType getMessageType() const;
216
217
    /// Set the Message Type
218
    /// @param[in] type Type to set
219
    void setMessageType(MsgType type);
220
221
    /// Set the Message Type
222
    /// @param[in] type Type to set
223
    void setMessageType(uint8_t type);
224
225
    /// Get the returnCode
226
    /// @return uint8_t
227
    uint8_t getReturnCode() const;
228
229
    /// Set the returnCode
230
    /// @param[in] returnCode ReturnCode to set
231
    void setReturnCode(uint8_t returnCode);
232
233
    /// Set the length field of the SOME/IP header
234
    /// @param[in] payloadLength Length of the payload
235
    void setPayloadLength(uint32_t payloadLength);
236
237
    /// @return A pointer for the layer payload, meaning the first byte after the header
238
    uint8_t* getPduPayload() const
239
0
    {
240
0
      return m_Data + getSomeIpHeaderLen();
241
0
    }
242
243
    /// @return The size in bytes of the payload
244
    size_t getPduPayloadSize() const
245
0
    {
246
0
      return getHeaderLen() - getSomeIpHeaderLen();
247
0
    }
248
249
    /// Get the Length of the SOME/IP header inc payload
250
    /// @return size_t
251
    size_t getHeaderLen() const override
252
58.4k
    {
253
58.4k
      return sizeof(uint32_t) * 2 + getLengthField();
254
58.4k
    }
255
256
    /// Does nothing for this layer
257
    virtual void computeCalculateFields() override
258
2.43k
    {}
259
260
    /// Identifies the following next layers: SomeIpLayer, SomeIpTpLayer, SomeIpSdLayer. Otherwise sets PayloadLayer
261
    void parseNextLayer() override;
262
263
    /// @return The string representation of the SOME/IP layer
264
    virtual std::string toString() const override;
265
266
    /// @return The OSI model layer of this layer
267
    OsiModelLayer getOsiModelLayer() const override
268
9.56k
    {
269
9.56k
      return OsiModelApplicationLayer;
270
9.56k
    }
271
272
    /// @struct SerializedFields
273
    /// Fields written by SomeIpLayer's serializeLayer(), in addition to
274
    /// Layer::SerializedFields.
275
    struct SerializedFields : Layer::SerializedFields
276
    {
277
      /// @return All field descriptors for SomeIpLayer
278
      static std::vector<FieldDescriptor> all()
279
0
      {
280
0
        auto result = Layer::SerializedFields::all();
281
0
        std::initializer_list<FieldDescriptor> extra{ ServiceID,   MethodID,        ClientID,
282
0
                                                    SessionID,   ProtocolVersion, InterfaceVersion,
283
0
                                                    MessageType, MessageTypeName, ReturnCode };
284
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
285
0
        return result;
286
0
      }
287
288
      /// @brief Field descriptor for the service ID, written as a hex value.
289
      static const FieldDescriptor ServiceID;
290
291
      /// @brief Field descriptor for the method ID, written as a hex value.
292
      static const FieldDescriptor MethodID;
293
294
      /// @brief Field descriptor for the client ID, written as a hex value.
295
      static const FieldDescriptor ClientID;
296
297
      /// @brief Field descriptor for the session ID, written as a number.
298
      static const FieldDescriptor SessionID;
299
300
      /// @brief Field descriptor for the protocol version, written as a number.
301
      static const FieldDescriptor ProtocolVersion;
302
303
      /// @brief Field descriptor for the interface version, written as a number.
304
      static const FieldDescriptor InterfaceVersion;
305
306
      /// @brief Field descriptor for the raw message type value, written as a number.
307
      static const FieldDescriptor MessageType;
308
309
      /// @brief Field descriptor for the message type name, written as a string (see SomeIpLayer::MsgType).
310
      static const FieldDescriptor MessageTypeName;
311
312
      /// @brief Field descriptor for the return code, written as a number.
313
      static const FieldDescriptor ReturnCode;
314
315
      // cppcheck-suppress duplInheritedMember
316
      /// Maximum field ID used by SomeIpLayer
317
      static constexpr uint16_t MaxID = Layer::SerializedFields::MaxID + 9;
318
    };
319
320
  protected:
321
    SomeIpLayer()
322
0
    {}
323
324
    void serializeLayer(ObjectScope& serializer) const override;
325
326
  private:
327
    static const uint8_t SOMEIP_PROTOCOL_VERSION = 1;
328
    virtual size_t getSomeIpHeaderLen() const
329
0
    {
330
0
      return sizeof(someiphdr);
331
0
    }
332
333
    // Using unordered_set since insertion and search should be almost constant time
334
    static std::unordered_set<uint16_t> m_SomeIpPorts;
335
  };
336
337
  /// @class SomeIpTpLayer
338
  /// Represents an SOME/IP Transport Protocol Layer
339
  class SomeIpTpLayer : public SomeIpLayer
340
  {
341
  public:
342
    /// @struct someiptphdr
343
    /// Represents an SOME/IP-TP protocol header.
344
#pragma pack(push, 1)
345
    struct someiptphdr : someiphdr
346
    {
347
      /// Contains the offset and the more segments flag. 28 bit offset field measured in 16 bytes + 3 bit
348
      /// reserved + 1 bit more segments flag
349
      uint32_t offsetAndFlag;
350
    };
351
#pragma pack(pop)
352
    static_assert(sizeof(someiptphdr) == 20, "someiptphdr size is not 20 bytes");
353
354
    /// A constructor that creates the layer from an existing packet raw data
355
    /// @param[in] data A pointer to the raw data (will be casted to @ref someiptphdr)
356
    /// @param[in] dataLen Size of the data in bytes
357
    /// @param[in] prevLayer A pointer to the previous layer
358
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
359
    SomeIpTpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
360
250
        : SomeIpLayer(data, dataLen, prevLayer, packet)
361
250
    {}
362
363
    /// A constructor that creates empty layer and sets values
364
    /// @param[in] serviceID Service ID
365
    /// @param[in] methodID Method ID
366
    /// @param[in] clientID Client ID
367
    /// @param[in] sessionID Session ID
368
    /// @param[in] interfaceVersion Interface Version
369
    /// @param[in] type Type of the message
370
    /// @param[in] returnCode Return Code
371
    /// @param[in] offset Offset indicating the data offset in increments of 16 bytes
372
    /// @param[in] moreSegmentsFlag Flag indicating whether more SOME/IP-TP Packets will follow
373
    /// @param[in] data A pointer to the raw data
374
    /// @param[in] dataLen Size of the data in bytes
375
    SomeIpTpLayer(uint16_t serviceID, uint16_t methodID, uint16_t clientID, uint16_t sessionID,
376
                  uint8_t interfaceVersion, MsgType type, uint8_t returnCode, uint32_t offset,
377
                  bool moreSegmentsFlag, const uint8_t* const data = nullptr, size_t dataLen = 0);
378
379
    /// Destroy the layer object
380
    ~SomeIpTpLayer() override = default;
381
382
    /// Get a pointer to the basic SOME/IP-TP header. Notice this points directly to the data, so every change will
383
    /// change the actual packet data
384
    /// @return A pointer to the @ref someiptphdr
385
    someiptphdr* getSomeIpTpHeader() const
386
0
    {
387
0
      return reinterpret_cast<someiptphdr*>(m_Data);
388
0
    }
389
390
    /// Get the Offset. Offset is returned in multiple of 16 bytes.
391
    /// @return The offset value
392
    uint32_t getOffset() const;
393
394
    /// Set the Offset. Already has to be in multiples of 16 bytes.
395
    /// If 32 bytes have already been transmitted, the offset has to be set to 2.
396
    /// @param[in] offset Offset to set. Already has to be in multiples of 16 bytes.
397
    /// @throw std::invalid_argument if offset isn't a multiple of 16
398
    void setOffset(uint32_t offset);
399
400
    /// Get the More Segments Flag
401
    /// @return true if the More Segments Flag is set, false if it is not set
402
    bool getMoreSegmentsFlag() const;
403
404
    /// Set the More Segments Flag
405
    /// @param[in] flag True if the More Segments Flag shall be set, false for resetting
406
    void setMoreSegmentsFlag(bool flag);
407
408
    /// Sets the message type in this layer with enabling the TP flag
409
    void computeCalculateFields() override;
410
411
    /// @return The string representation of the SOME/IP-TP layer
412
    std::string toString() const override;
413
414
    /// @struct SerializedFields
415
    /// Fields written by SomeIpTpLayer's serializeLayer(), in addition to
416
    /// SomeIpLayer::SerializedFields.
417
    struct SerializedFields : SomeIpLayer::SerializedFields
418
    {
419
      /// @return All field descriptors for SomeIpTpLayer
420
      static std::vector<FieldDescriptor> all()
421
0
      {
422
0
        auto result = SomeIpLayer::SerializedFields::all();
423
0
        std::initializer_list<FieldDescriptor> extra{ Offset, MoreSegments };
424
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
425
0
        return result;
426
0
      }
427
428
      /// @brief Field descriptor for the offset of the segment payload in the original message (in bytes),
429
      /// written as a number. Always a multiple of 16.
430
      static const FieldDescriptor Offset;
431
432
      /// @brief Field descriptor for the More Segments flag, written as a boolean.
433
      static const FieldDescriptor MoreSegments;
434
    };
435
436
  protected:
437
    void serializeLayer(ObjectScope& serializer) const override;
438
439
  private:
440
    static const uint32_t SOMEIP_TP_MORE_FLAG_MASK = 0x01;
441
    static const uint32_t SOMEIP_TP_OFFSET_MASK = 0xFFFFFFF0;
442
443
    size_t getSomeIpHeaderLen() const override
444
0
    {
445
0
      return sizeof(someiptphdr);
446
0
    }
447
448
    static uint8_t setTpFlag(uint8_t messageType);
449
  };
450
451
}  // namespace pcpp