Coverage Report

Created: 2026-10-17 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/header/GvcpLayer.h
Line
Count
Source
1
#pragma once
2
3
#include "IpAddress.h"
4
#include "Layer.h"
5
#include "MacAddress.h"
6
#include <algorithm>
7
#include <initializer_list>
8
#include <iterator>
9
#include <ostream>
10
#include <string>
11
12
/// @file
13
/// This file contains classes for parsing, creating and editing GVCP (GigE Vision Control Protocol) packets.
14
/// The implementation is based on the GigE Vision (R) Specification version 2.0
15
16
/// @namespace pcpp
17
/// @brief The main namespace for the PcapPlusPlus lib
18
namespace pcpp
19
{
20
  /// GVCP flag. The meaning of bits 0-3 is specified by each command, bits 4-6 are reserved and bit 7 (the least
21
  /// significant bit) is the acknowledge-required bit
22
  using GvcpFlag = uint8_t;
23
24
  /// @class GvcpLayer
25
  /// An abstract class representing the GigE Vision Control Protocol (GVCP).
26
  /// The class is implemented according to the GigE Vision specification 2.0.
27
  /// A GVCP layer holds the GVCP header, followed by the message fields that its class knows how to parse.
28
  /// parseNextLayer() puts the rest of the message, if any, in a PayloadLayer
29
  /// @see https://en.wikipedia.org/wiki/GigE_Vision
30
  /// @note The class cannot be instantiated directly, use GvcpRequestLayer, GvcpAcknowledgeLayer or their derived
31
  /// classes
32
  class GvcpLayer : public Layer
33
  {
34
  public:
35
    /// GVCP command defines the command values and the corresponding acknowledge values.
36
    /// See more in the spec "18 Command and Acknowledge Values"
37
    enum class GvcpCommand : uint16_t
38
    {
39
      /// Discovery command (Discovery Protocol Control)
40
      DiscoveredCmd = 0x0002,
41
      /// Discovery acknowledge (Discovery Protocol Control)
42
      DiscoveredAck = 0x0003,
43
      /// Force IP command (Discovery Protocol Control)
44
      ForceIpCmd = 0x0004,
45
      /// Force IP acknowledge (Discovery Protocol Control)
46
      ForceIpAck = 0x0005,
47
48
      /// Packet resend command (Streaming Protocol Control)
49
      PacketResendCmd = 0x0040,
50
      /// Packet resend acknowledge (Streaming Protocol Control). The resent packet must be on the stream channel
51
      PacketResendAck = 0x0041,
52
53
      /// Read register command (Device Memory Access)
54
      ReadRegCmd = 0x0080,
55
      /// Read register acknowledge (Device Memory Access)
56
      ReadRegAck = 0x0081,
57
      /// Write register command (Device Memory Access)
58
      WriteRegCmd = 0x0082,
59
      /// Write register acknowledge (Device Memory Access)
60
      WriteRegAck = 0x0083,
61
      /// Read memory command (Device Memory Access)
62
      ReadMemCmd = 0x0084,
63
      /// Read memory acknowledge (Device Memory Access)
64
      ReadMemAck = 0x0085,
65
      /// Write memory command (Device Memory Access)
66
      WriteMemCmd = 0x0086,
67
      /// Write memory acknowledge (Device Memory Access)
68
      WriteMemAck = 0x0087,
69
      /// Pending acknowledge (Device Memory Access)
70
      PendingAck = 0x0089,
71
72
      /// Event command (Asynchronous Events)
73
      EventCmd = 0x00C0,
74
      /// Event acknowledge (Asynchronous Events)
75
      EventAck = 0x00C1,
76
      /// Event data command (Asynchronous Events)
77
      EventDataCmd = 0x00C2,
78
      /// Event data acknowledge (Asynchronous Events)
79
      EventDataAck = 0x00C3,
80
81
      /// Action command (Miscellaneous)
82
      ActionCmd = 0x0100,
83
      /// Action acknowledge (Miscellaneous)
84
      ActionAck = 0x0101,
85
86
      /// Unknown command
87
      Unknown = 0xFFFF
88
    };
89
90
    /// A static method that checks whether the port is considered as GVCP
91
    /// @param[in] port The port number to be checked
92
    /// @return True if the port is the GVCP port (3956), false otherwise
93
    static bool isGvcpPort(uint16_t port)
94
190k
    {
95
190k
      return port == 3956;
96
190k
    }
97
98
    /// A static method that parses the raw data and creates the matching GVCP layer. If the data begins with the
99
    /// GVCP magic number, the method creates a request layer, otherwise an acknowledge layer. For Discovery and
100
    /// Force IP messages, the method creates their specific layers, unless the data is too short for the fields of
101
    /// these messages
102
    /// @param[in] data A pointer to the raw data
103
    /// @param[in] dataLen Size of the data in bytes
104
    /// @param[in] prevLayer A pointer to the previous layer
105
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
106
    /// @return A pointer to the newly created GVCP layer, or nullptr if the data isn't a valid GVCP message
107
    static GvcpLayer* parseGvcpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
108
109
    /// @return The command (or acknowledge) value of this message, GvcpCommand::Unknown if the value isn't
110
    /// defined by the spec
111
    virtual GvcpCommand getCommand() const = 0;
112
113
    /// @return The data size field from the header, meaning the size of the message without the GVCP header
114
    virtual uint16_t getDataSize() const = 0;
115
116
    // Overridden methods
117
118
    /// Creates a PayloadLayer from the rest of the message, if there is data after this layer
119
    void parseNextLayer() override;
120
121
    /// @return The OSI Model layer this protocol belongs to
122
    OsiModelLayer getOsiModelLayer() const override
123
0
    {
124
0
      return OsiModelApplicationLayer;
125
0
    }
126
127
    /// @struct SerializedFields
128
    /// Fields written by GvcpLayer's serializeLayer(), in addition to
129
    /// Layer::SerializedFields.
130
    struct SerializedFields : Layer::SerializedFields
131
    {
132
      /// @return All field descriptors for GvcpLayer
133
      static std::vector<FieldDescriptor> all()
134
0
      {
135
0
        auto result = Layer::SerializedFields::all();
136
0
        std::initializer_list<FieldDescriptor> extra{ Command, CommandName };
137
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
138
0
        return result;
139
0
      }
140
141
      /// @brief Command or acknowledge value
142
      static const FieldDescriptor Command;
143
144
      /// @brief Name of the command or acknowledge value, or "Unknown"
145
      static const FieldDescriptor CommandName;
146
147
      // cppcheck-suppress duplInheritedMember
148
      /// Maximum field ID used by GvcpLayer
149
      static constexpr uint16_t MaxID = Layer::SerializedFields::MaxID + 2;
150
    };
151
152
  protected:
153
    void serializeLayer(ObjectScope& serializer) const override;
154
155
0
    GvcpLayer() = default;
156
157
    GvcpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
158
0
        : Layer(data, dataLen, prevLayer, packet, GVCP)
159
0
    {}
160
161
    /// Allocate zeroed data for a new layer and set the protocol
162
    /// @param[in] dataLen The size of the data to allocate in bytes
163
    void initLayer(size_t dataLen);
164
165
  private:
166
    /// @return The command field of a GVCP request or acknowledge in host byte order, also when the spec doesn't
167
    /// define the value
168
    static uint16_t getRawCommand(const uint8_t* data);
169
  };
170
171
  /// Output operator for GvcpLayer::GvcpCommand, prints the command name, or "Unknown" if the value isn't defined by
172
  /// the spec
173
  std::ostream& operator<<(std::ostream& os, GvcpLayer::GvcpCommand command);
174
175
  /// @class GvcpRequestLayer
176
  /// Represents a GVCP request (command) message. Commands which don't have a specific layer class are
177
  /// represented by this class
178
  class GvcpRequestLayer : public GvcpLayer
179
  {
180
  public:
181
    /// A constructor that creates the layer from an existing packet raw data
182
    /// @param[in] data A pointer to the raw data
183
    /// @param[in] dataLen Size of the data in bytes
184
    /// @param[in] prevLayer A pointer to the previous layer
185
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
186
    GvcpRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
187
0
        : GvcpLayer(data, dataLen, prevLayer, packet)
188
0
    {}
189
190
    /// A constructor that creates a new GVCP request which contains only the GVCP header. To add message data,
191
    /// add a PayloadLayer after this layer
192
    /// @param[in] command The command
193
    /// @param[in] flag The flag, optional
194
    /// @param[in] requestId The request ID, optional. The spec requires a non-zero value
195
    /// @throw std::invalid_argument if the command is an acknowledge value (an odd value)
196
    explicit GvcpRequestLayer(GvcpCommand command, GvcpFlag flag = 0, uint16_t requestId = 1)
197
0
        : GvcpRequestLayer(command, flag, requestId, 0)
198
0
    {}
199
200
    /// A static method that checks whether the data is a valid GVCP request. The data must be large enough to hold
201
    /// a GVCP request header and must begin with the GVCP magic number
202
    /// @param[in] data A pointer to the raw data
203
    /// @param[in] dataLen Size of the data in bytes
204
    /// @return True if the data is a valid GVCP request, false otherwise
205
    static bool isDataValid(const uint8_t* data, size_t dataLen);
206
207
    /// @return The flag from the header
208
    GvcpFlag getFlag() const;
209
210
    /// Set the flag in the header
211
    /// @param[in] flag The flag to set
212
    void setFlag(GvcpFlag flag);
213
214
    /// @return True if the acknowledge-required bit is set in the flag, false otherwise
215
    bool hasAcknowledgeFlag() const;
216
217
    /// @return The request ID from the header
218
    uint16_t getRequestId() const;
219
220
    /// Set the request ID in the header
221
    /// @param[in] requestId The request ID to set
222
    void setRequestId(uint16_t requestId);
223
224
    // Overridden methods
225
226
    /// @return The command from the header, GvcpCommand::Unknown if the value isn't defined by the spec
227
    GvcpCommand getCommand() const override;
228
229
    /// @return The data size from the header
230
    uint16_t getDataSize() const override;
231
232
    /// @return The size of the GVCP request header
233
    size_t getHeaderLen() const override
234
0
    {
235
0
      return sizeof(gvcp_request_header);
236
0
    }
237
238
    /// Calculate the data size field in the header according to the size of the data that follows the header
239
    void computeCalculateFields() override;
240
241
    /// @return A string representation of the layer most important data
242
    std::string toString() const override;
243
244
    /// @struct SerializedFields
245
    /// Fields written by GvcpRequestLayer's serializeLayer(), in addition to
246
    /// GvcpLayer::SerializedFields.
247
    struct SerializedFields : GvcpLayer::SerializedFields
248
    {
249
      /// @return All field descriptors for GvcpRequestLayer
250
      static std::vector<FieldDescriptor> all()
251
0
      {
252
0
        auto result = GvcpLayer::SerializedFields::all();
253
0
        std::initializer_list<FieldDescriptor> extra{ Flag, AcknowledgeRequired, RequestId };
254
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
255
0
        return result;
256
0
      }
257
258
      /// @brief Flag from the header
259
      static const FieldDescriptor Flag;
260
261
      /// @brief Whether the acknowledge-required bit is set
262
      static const FieldDescriptor AcknowledgeRequired;
263
264
      /// @brief Request ID
265
      static const FieldDescriptor RequestId;
266
267
      // cppcheck-suppress duplInheritedMember
268
      /// Maximum field ID used by GvcpRequestLayer
269
      static constexpr uint16_t MaxID = GvcpLayer::SerializedFields::MaxID + 3;
270
    };
271
272
  protected:
273
    void serializeLayer(ObjectScope& serializer) const override;
274
275
#pragma pack(push, 1)
276
    /// @struct gvcp_request_header
277
    /// GVCP request header, see the spec "15.1 Request Header". The data is stored as big-endian.
278
    struct gvcp_request_header
279
    {
280
      /// Magic number, always 0x42
281
      uint8_t magicNumber;
282
      /// GVCP flag
283
      uint8_t flag;
284
      /// Command
285
      uint16_t command;
286
      /// Data size (the size of the message without the header)
287
      uint16_t dataSize;
288
      /// Request ID
289
      uint16_t requestId;
290
    };
291
#pragma pack(pop)
292
    static_assert(sizeof(gvcp_request_header) == 8, "gvcp_request_header size is not 8 bytes");
293
294
    /// A constructor that creates a new GVCP request with a message body of zeroed bytes after the header
295
    /// @param[in] command The command
296
    /// @param[in] flag The flag
297
    /// @param[in] requestId The request ID
298
    /// @param[in] bodyLen The size of the message body in bytes
299
    /// @throw std::invalid_argument if the command is an acknowledge value (an odd value)
300
    GvcpRequestLayer(GvcpCommand command, GvcpFlag flag, uint16_t requestId, size_t bodyLen);
301
302
  private:
303
    // GvcpLayer::parseGvcpLayer() reads the command from the header
304
    friend class GvcpLayer;
305
306
    gvcp_request_header* getGvcpHeader() const
307
0
    {
308
0
      return reinterpret_cast<gvcp_request_header*>(m_Data);
309
0
    }
310
  };
311
312
  /// @class GvcpAcknowledgeLayer
313
  /// Represents a GVCP acknowledge message. Acknowledges which don't have a specific layer class are
314
  /// represented by this class
315
  class GvcpAcknowledgeLayer : public GvcpLayer
316
  {
317
  public:
318
    /// GVCP response status can be returned in an acknowledge message or a GVSP header.
319
    /// See more in the spec "Table 19-1: List of Standard Status Codes"
320
    enum class GvcpResponseStatus : uint16_t
321
    {
322
      /// Command executed successfully
323
      Success = 0x0000,
324
      /// Only applies to packet being resent
325
      PacketResend = 0x0100,
326
      /// Command is not supported by the device
327
      NotImplemented = 0x8001,
328
      /// At least one parameter provided in the command is invalid (or out of range) for the device
329
      InvalidParameter = 0x8002,
330
      /// An attempt was made to access a non-existent address space location
331
      InvalidAddress = 0x8003,
332
      /// The addressed register cannot be written to
333
      WriteProtect = 0x8004,
334
      /// A badly aligned address offset or data size was specified
335
      BadAlignment = 0x8005,
336
      /// An attempt was made to access an address location which is currently/momentary not accessible
337
      AccessDenied = 0x8006,
338
      /// A required resource to service the request is not currently available. The request may be retried at a
339
      /// later time
340
      Busy = 0x8007,
341
      /// Deprecated
342
      LocalProblem = 0x8008,
343
      /// Deprecated
344
      MsgMismatch = 0x8009,
345
      /// Deprecated
346
      InvalidProtocol = 0x800A,
347
      /// Deprecated
348
      NoMsg = 0x800B,
349
      /// The requested packet is not available anymore
350
      PacketUnavailable = 0x800C,
351
      /// Internal memory of GVSP transmitter overrun (typically for image acquisition)
352
      DataOverrun = 0x800D,
353
      /// The message header is not valid. Some of its fields do not match the specification
354
      InvalidHeader = 0x800E,
355
      /// Deprecated
356
      WrongConfig = 0x800F,
357
      /// The requested packet has not yet been acquired. Can be used for linescan cameras device when line
358
      /// trigger rate is slower than application timeout
359
      PacketNotYetAvailable = 0x8010,
360
      /// The requested packet and all previous ones are not available anymore and have been discarded from the
361
      /// GVSP transmitter memory
362
      PacketAndPrevRemovedFromMemory = 0x8011,
363
      /// The requested packet is not available anymore and has been discarded from the GVSP transmitter memory
364
      PacketRemovedFromMemory = 0x8012,
365
      /// The device is not synchronized to a master clock to be used as time reference
366
      NoRefTime = 0x8013,
367
      /// The packet cannot be resent at the moment due to temporary bandwidth issues and should be requested
368
      /// again in the future
369
      PacketTemporarilyUnavailable = 0x8014,
370
      /// A device queue or packet data has overflowed
371
      Overflow = 0x8015,
372
      /// The requested scheduled action command was requested at a time that is already past
373
      ActionLate = 0x8016,
374
      /// Leader or trailer overflow (GEV 2.1)
375
      LeaderTrailerOverflow = 0x8017,
376
      /// Generic error
377
      Error = 0x8FFF,
378
      /// Unknown status
379
      Unknown = 0xFFFF
380
    };
381
382
    /// A constructor that creates the layer from an existing packet raw data
383
    /// @param[in] data A pointer to the raw data
384
    /// @param[in] dataLen Size of the data in bytes
385
    /// @param[in] prevLayer A pointer to the previous layer
386
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
387
    GvcpAcknowledgeLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
388
0
        : GvcpLayer(data, dataLen, prevLayer, packet)
389
0
    {}
390
391
    /// A constructor that creates a new GVCP acknowledge which contains only the GVCP header. To add message
392
    /// data, add a PayloadLayer after this layer
393
    /// @param[in] status The response status
394
    /// @param[in] command The acknowledge value
395
    /// @param[in] ackId The acknowledge ID, optional
396
    /// @throw std::invalid_argument if the acknowledge value is a command value (an even value)
397
    GvcpAcknowledgeLayer(GvcpResponseStatus status, GvcpCommand command, uint16_t ackId = 0)
398
        : GvcpAcknowledgeLayer(status, command, ackId, 0)
399
0
    {}
400
401
    /// A static method that checks whether the data is large enough to hold a GVCP acknowledge header
402
    /// @param[in] data A pointer to the raw data
403
    /// @param[in] dataLen Size of the data in bytes
404
    /// @return True if the data can be parsed as a GVCP acknowledge, false otherwise
405
    static bool isDataValid(const uint8_t* data, size_t dataLen);
406
407
    /// @return The response status from the header, GvcpResponseStatus::Unknown if the value isn't defined by the
408
    /// spec
409
    GvcpResponseStatus getStatus() const;
410
411
    /// Set the response status in the header
412
    /// @param[in] status The response status to set
413
    void setStatus(GvcpResponseStatus status);
414
415
    /// @return The acknowledge ID from the header
416
    uint16_t getAckId() const;
417
418
    /// Set the acknowledge ID in the header
419
    /// @param[in] ackId The acknowledge ID to set
420
    void setAckId(uint16_t ackId);
421
422
    // Overridden methods
423
424
    /// @return The acknowledge value from the header, GvcpCommand::Unknown if the value isn't defined by the spec
425
    GvcpCommand getCommand() const override;
426
427
    /// @return The data size from the header
428
    uint16_t getDataSize() const override;
429
430
    /// @return The size of the GVCP acknowledge header
431
    size_t getHeaderLen() const override
432
0
    {
433
0
      return sizeof(gvcp_ack_header);
434
0
    }
435
436
    /// Calculate the data size field in the header according to the size of the data that follows the header
437
    void computeCalculateFields() override;
438
439
    /// @return A string representation of the layer most important data
440
    std::string toString() const override;
441
442
    /// @struct SerializedFields
443
    /// Fields written by GvcpAcknowledgeLayer's serializeLayer(), in addition to
444
    /// GvcpLayer::SerializedFields.
445
    struct SerializedFields : GvcpLayer::SerializedFields
446
    {
447
      /// @return All field descriptors for GvcpAcknowledgeLayer
448
      static std::vector<FieldDescriptor> all()
449
0
      {
450
0
        auto result = GvcpLayer::SerializedFields::all();
451
0
        std::initializer_list<FieldDescriptor> extra{ Status, StatusName, AckId };
452
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
453
0
        return result;
454
0
      }
455
456
      /// @brief Response status value
457
      static const FieldDescriptor Status;
458
459
      /// @brief Name of the response status, or "Unknown"
460
      static const FieldDescriptor StatusName;
461
462
      /// @brief Acknowledge ID
463
      static const FieldDescriptor AckId;
464
465
      // cppcheck-suppress duplInheritedMember
466
      /// Maximum field ID used by GvcpAcknowledgeLayer
467
      static constexpr uint16_t MaxID = GvcpLayer::SerializedFields::MaxID + 3;
468
    };
469
470
  protected:
471
    void serializeLayer(ObjectScope& serializer) const override;
472
473
#pragma pack(push, 1)
474
    /// @struct gvcp_ack_header
475
    /// GVCP acknowledge header, see the spec "15.2 Acknowledge Header". The data is stored as big-endian.
476
    struct gvcp_ack_header
477
    {
478
      /// Response status
479
      uint16_t status;
480
      /// Command
481
      uint16_t command;
482
      /// Data size (the size of the message without the header)
483
      uint16_t dataSize;
484
      /// Acknowledge ID
485
      uint16_t ackId;
486
    };
487
#pragma pack(pop)
488
    static_assert(sizeof(gvcp_ack_header) == 8, "gvcp_ack_header size is not 8 bytes");
489
490
    /// A constructor that creates a new GVCP acknowledge with a message body of zeroed bytes after the header
491
    /// @param[in] status The response status
492
    /// @param[in] command The acknowledge value
493
    /// @param[in] ackId The acknowledge ID
494
    /// @param[in] bodyLen The size of the message body in bytes
495
    /// @throw std::invalid_argument if the acknowledge value is a command value (an even value)
496
    GvcpAcknowledgeLayer(GvcpResponseStatus status, GvcpCommand command, uint16_t ackId, size_t bodyLen);
497
498
  private:
499
    // GvcpLayer::parseGvcpLayer() reads the command from the header
500
    friend class GvcpLayer;
501
502
    gvcp_ack_header* getGvcpHeader() const
503
0
    {
504
0
      return reinterpret_cast<gvcp_ack_header*>(m_Data);
505
0
    }
506
  };
507
508
  /// Output operator for GvcpAcknowledgeLayer::GvcpResponseStatus, prints the status name, or "Unknown" if the value
509
  /// isn't defined by the spec
510
  std::ostream& operator<<(std::ostream& os, GvcpAcknowledgeLayer::GvcpResponseStatus status);
511
512
  /// @class GvcpDiscoveryRequestLayer
513
  /// Represents a GVCP discovery command (DISCOVERY_CMD)
514
  class GvcpDiscoveryRequestLayer : public GvcpRequestLayer
515
  {
516
  public:
517
    /// A constructor that creates the layer from an existing packet raw data
518
    /// @param[in] data A pointer to the raw data
519
    /// @param[in] dataLen Size of the data in bytes
520
    /// @param[in] prevLayer A pointer to the previous layer
521
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
522
    GvcpDiscoveryRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
523
0
        : GvcpRequestLayer(data, dataLen, prevLayer, packet)
524
0
    {}
525
526
    /// A constructor that creates a new GVCP discovery command
527
    /// @param[in] allowBroadcastAck Whether the device is allowed to broadcast the acknowledge, optional
528
    /// @param[in] acknowledgeRequired Whether an acknowledge is required, optional
529
    /// @param[in] requestId The request ID, optional. The spec requires a non-zero value
530
    explicit GvcpDiscoveryRequestLayer(bool allowBroadcastAck = false, bool acknowledgeRequired = true,
531
                                       uint16_t requestId = 1);
532
533
    /// @return True if the allow-broadcast-acknowledge bit is set in the flag, meaning the device is allowed to
534
    /// broadcast the acknowledge, false otherwise
535
    bool hasAllowBroadcastAckFlag() const;
536
537
    /// Set or clear the allow-broadcast-acknowledge bit in the flag
538
    /// @param[in] allowBroadcastAck True to set the bit, false to clear it
539
    void setAllowBroadcastAckFlag(bool allowBroadcastAck);
540
    /// @struct SerializedFields
541
    /// Fields written by GvcpDiscoveryRequestLayer's serializeLayer(), in addition to
542
    /// GvcpRequestLayer::SerializedFields.
543
    struct SerializedFields : GvcpRequestLayer::SerializedFields
544
    {
545
      /// @return All field descriptors for GvcpDiscoveryRequestLayer
546
      static std::vector<FieldDescriptor> all()
547
0
      {
548
0
        auto result = GvcpRequestLayer::SerializedFields::all();
549
0
        std::initializer_list<FieldDescriptor> extra{ AllowBroadcastAck };
550
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
551
0
        return result;
552
0
      }
553
554
      /// @brief Whether the allow-broadcast-acknowledge bit is set
555
      static const FieldDescriptor AllowBroadcastAck;
556
557
      // cppcheck-suppress duplInheritedMember
558
      /// Maximum field ID used by GvcpDiscoveryRequestLayer
559
      static constexpr uint16_t MaxID = GvcpRequestLayer::SerializedFields::MaxID + 1;
560
    };
561
562
  protected:
563
    void serializeLayer(ObjectScope& serializer) const override;
564
  };
565
566
  /// @class GvcpDiscoveryAcknowledgeLayer
567
  /// Represents a GVCP discovery acknowledge (DISCOVERY_ACK)
568
  class GvcpDiscoveryAcknowledgeLayer : public GvcpAcknowledgeLayer
569
  {
570
  public:
571
    /// @struct GvcpVersion
572
    /// The GigE Vision spec version
573
    struct GvcpVersion
574
    {
575
      /// The version major number
576
      uint16_t major;
577
      /// The version minor number
578
      uint16_t minor;
579
    };
580
581
    /// A constructor that creates the layer from an existing packet raw data
582
    /// @param[in] data A pointer to the raw data
583
    /// @param[in] dataLen Size of the data in bytes
584
    /// @param[in] prevLayer A pointer to the previous layer
585
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
586
    GvcpDiscoveryAcknowledgeLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
587
0
        : GvcpAcknowledgeLayer(data, dataLen, prevLayer, packet)
588
0
    {}
589
590
    /// A constructor that creates a new GVCP discovery acknowledge. The constructor sets all of the discovery
591
    /// fields to zero. Use the setters of this class to set them
592
    /// @param[in] status The response status, optional
593
    /// @param[in] ackId The acknowledge ID, optional
594
    explicit GvcpDiscoveryAcknowledgeLayer(GvcpResponseStatus status = GvcpResponseStatus::Success,
595
                                           uint16_t ackId = 0);
596
597
    // cppcheck-suppress duplInheritedMember
598
    /// A static method that checks whether the data is large enough to hold a GVCP discovery acknowledge
599
    /// @param[in] data A pointer to the raw data
600
    /// @param[in] dataLen Size of the data in bytes
601
    /// @return True if the data can be parsed as a GVCP discovery acknowledge, false otherwise
602
    static bool isDataValid(const uint8_t* data, size_t dataLen);
603
604
    /// @return The GigE Vision spec version supported by the device
605
    GvcpVersion getVersion() const;
606
607
    /// Set the GigE Vision spec version supported by the device
608
    /// @param[in] version The version to set
609
    void setVersion(const GvcpVersion& version);
610
611
    /// @return The device MAC address
612
    MacAddress getMacAddress() const;
613
614
    /// Set the device MAC address
615
    /// @param[in] macAddress The MAC address to set
616
    void setMacAddress(const MacAddress& macAddress);
617
618
    /// @return The device IP address
619
    IPv4Address getIpAddress() const;
620
621
    /// Set the device IP address
622
    /// @param[in] ipAddress The IP address to set
623
    void setIpAddress(const IPv4Address& ipAddress);
624
625
    /// @return The device subnet mask
626
    IPv4Address getSubnetMask() const;
627
628
    /// Set the device subnet mask
629
    /// @param[in] subnetMask The subnet mask to set
630
    void setSubnetMask(const IPv4Address& subnetMask);
631
632
    /// @return The device default gateway IP address
633
    IPv4Address getGatewayIpAddress() const;
634
635
    /// Set the device default gateway IP address
636
    /// @param[in] gatewayIpAddress The default gateway IP address to set
637
    void setGatewayIpAddress(const IPv4Address& gatewayIpAddress);
638
639
    /// @return The manufacturer name
640
    std::string getManufacturerName() const;
641
642
    /// Set the manufacturer name
643
    /// @param[in] manufacturerName The manufacturer name to set, truncated if longer than 31 characters
644
    void setManufacturerName(const std::string& manufacturerName);
645
646
    /// @return The model name
647
    std::string getModelName() const;
648
649
    /// Set the model name
650
    /// @param[in] modelName The model name to set, truncated if longer than 31 characters
651
    void setModelName(const std::string& modelName);
652
653
    /// @return The device version
654
    std::string getDeviceVersion() const;
655
656
    /// Set the device version
657
    /// @param[in] deviceVersion The device version to set, truncated if longer than 31 characters
658
    void setDeviceVersion(const std::string& deviceVersion);
659
660
    /// @return The manufacturer specific information
661
    std::string getManufacturerSpecificInformation() const;
662
663
    /// Set the manufacturer specific information
664
    /// @param[in] info The manufacturer specific information to set, truncated if longer than 47 characters
665
    void setManufacturerSpecificInformation(const std::string& info);
666
667
    /// @return The serial number
668
    std::string getSerialNumber() const;
669
670
    /// Set the serial number
671
    /// @param[in] serialNumber The serial number to set, truncated if longer than 15 characters
672
    void setSerialNumber(const std::string& serialNumber);
673
674
    /// @return The user defined name
675
    std::string getUserDefinedName() const;
676
677
    /// Set the user defined name
678
    /// @param[in] userDefinedName The user defined name to set, truncated if longer than 15 characters
679
    void setUserDefinedName(const std::string& userDefinedName);
680
681
    // Overridden methods
682
683
    /// @return The size of the GVCP header and the discovery acknowledge body
684
    size_t getHeaderLen() const override
685
0
    {
686
0
      return sizeof(gvcp_ack_header) + sizeof(gvcp_discovery_body);
687
0
    }
688
689
    /// @struct SerializedFields
690
    /// Fields written by GvcpDiscoveryAcknowledgeLayer's serializeLayer(), in addition to
691
    /// GvcpAcknowledgeLayer::SerializedFields.
692
    struct SerializedFields : GvcpAcknowledgeLayer::SerializedFields
693
    {
694
      /// @return All field descriptors for GvcpDiscoveryAcknowledgeLayer
695
      static std::vector<FieldDescriptor> all()
696
0
      {
697
0
        auto result = GvcpAcknowledgeLayer::SerializedFields::all();
698
0
        std::initializer_list<FieldDescriptor> extra{
699
0
          VersionMajor,     VersionMinor,     MacAddress, IpAddress,     SubnetMask,
700
0
          GatewayIpAddress, ManufacturerName, ModelName,  DeviceVersion, ManufacturerSpecificInformation,
701
0
          SerialNumber,     UserDefinedName
702
0
        };
703
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
704
0
        return result;
705
0
      }
706
707
      /// @brief GigE Vision spec version major number
708
      static const FieldDescriptor VersionMajor;
709
710
      /// @brief GigE Vision spec version minor number
711
      static const FieldDescriptor VersionMinor;
712
713
      /// @brief Device MAC address, as a string
714
      static const FieldDescriptor MacAddress;
715
716
      /// @brief Device IP address, as a string
717
      static const FieldDescriptor IpAddress;
718
719
      /// @brief Device subnet mask, as a string
720
      static const FieldDescriptor SubnetMask;
721
722
      /// @brief Device default gateway IP address, as a string
723
      static const FieldDescriptor GatewayIpAddress;
724
725
      /// @brief Manufacturer name
726
      static const FieldDescriptor ManufacturerName;
727
728
      /// @brief Model name
729
      static const FieldDescriptor ModelName;
730
731
      /// @brief Device version
732
      static const FieldDescriptor DeviceVersion;
733
734
      /// @brief Manufacturer specific information
735
      static const FieldDescriptor ManufacturerSpecificInformation;
736
737
      /// @brief Serial number
738
      static const FieldDescriptor SerialNumber;
739
740
      /// @brief User defined name
741
      static const FieldDescriptor UserDefinedName;
742
743
      // cppcheck-suppress duplInheritedMember
744
      /// Maximum field ID used by GvcpDiscoveryAcknowledgeLayer
745
      static constexpr uint16_t MaxID = GvcpAcknowledgeLayer::SerializedFields::MaxID + 12;
746
    };
747
748
  protected:
749
    void serializeLayer(ObjectScope& serializer) const override;
750
751
  private:
752
#pragma pack(push, 1)
753
    /// GVCP discovery acknowledge body, see the spec "16.1.2 DISCOVERY_ACK". The data is stored as big-endian.
754
    struct gvcp_discovery_body
755
    {
756
      /// GigE Vision version major number
757
      uint16_t versionMajor;
758
      /// GigE Vision version minor number
759
      uint16_t versionMinor;
760
      /// Device mode
761
      uint32_t deviceMode;
762
      /// Reserved
763
      uint16_t reserved;
764
      /// MAC address
765
      uint8_t macAddress[6];
766
      /// Supported IP configuration options
767
      uint32_t supportedIpConfigOptions;
768
      /// Current IP configuration
769
      uint32_t ipConfigCurrent;
770
      /// Reserved
771
      uint8_t reserved2[12];
772
      /// IP address
773
      uint32_t ipAddress;
774
      /// Reserved
775
      uint8_t reserved3[12];
776
      /// Subnet mask
777
      uint32_t subnetMask;
778
      /// Reserved
779
      uint8_t reserved4[12];
780
      /// Default gateway
781
      uint32_t defaultGateway;
782
      /// Manufacturer name
783
      char manufacturerName[32];
784
      /// Model name
785
      char modelName[32];
786
      /// Device version
787
      char deviceVersion[32];
788
      /// Manufacturer specific information
789
      char manufacturerSpecificInformation[48];
790
      /// Serial number
791
      char serialNumber[16];
792
      /// User defined name
793
      char userDefinedName[16];
794
    };
795
#pragma pack(pop)
796
    static_assert(sizeof(gvcp_discovery_body) == 248, "gvcp_discovery_body size is not 248 bytes");
797
798
    gvcp_discovery_body* getGvcpDiscoveryBody() const
799
0
    {
800
0
      return reinterpret_cast<gvcp_discovery_body*>(m_Data + sizeof(gvcp_ack_header));
801
0
    }
802
  };
803
804
  /// @class GvcpForceIpRequestLayer
805
  /// Represents a GVCP force IP command (FORCEIP_CMD)
806
  class GvcpForceIpRequestLayer : public GvcpRequestLayer
807
  {
808
  public:
809
    /// A constructor that creates the layer from an existing packet raw data
810
    /// @param[in] data A pointer to the raw data
811
    /// @param[in] dataLen Size of the data in bytes
812
    /// @param[in] prevLayer A pointer to the previous layer
813
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
814
    GvcpForceIpRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
815
0
        : GvcpRequestLayer(data, dataLen, prevLayer, packet)
816
0
    {}
817
818
    /// A constructor that creates a new GVCP force IP command
819
    /// @param[in] macAddress The MAC address of the device to configure
820
    /// @param[in] ipAddress The IP address to force on the device
821
    /// @param[in] subnetMask The subnet mask to force on the device
822
    /// @param[in] gatewayIpAddress The default gateway to force on the device
823
    /// @param[in] flag The flag, optional
824
    /// @param[in] requestId The request ID, optional. The spec requires a non-zero value
825
    GvcpForceIpRequestLayer(const MacAddress& macAddress, const IPv4Address& ipAddress,
826
                            const IPv4Address& subnetMask, const IPv4Address& gatewayIpAddress, GvcpFlag flag = 0,
827
                            uint16_t requestId = 1);
828
829
    // cppcheck-suppress duplInheritedMember
830
    /// A static method that checks whether the data is a valid GVCP request which is large enough to hold a GVCP
831
    /// force IP command
832
    /// @param[in] data A pointer to the raw data
833
    /// @param[in] dataLen Size of the data in bytes
834
    /// @return True if the data can be parsed as a GVCP force IP command, false otherwise
835
    static bool isDataValid(const uint8_t* data, size_t dataLen);
836
837
    /// @return The MAC address of the device to configure
838
    MacAddress getMacAddress() const;
839
840
    /// Set the MAC address of the device to configure
841
    /// @param[in] macAddress The MAC address to set
842
    void setMacAddress(const MacAddress& macAddress);
843
844
    /// @return The IP address to force on the device
845
    IPv4Address getIpAddress() const;
846
847
    /// Set the IP address to force on the device
848
    /// @param[in] ipAddress The IP address to set
849
    void setIpAddress(const IPv4Address& ipAddress);
850
851
    /// @return The subnet mask to force on the device
852
    IPv4Address getSubnetMask() const;
853
854
    /// Set the subnet mask to force on the device
855
    /// @param[in] subnetMask The subnet mask to set
856
    void setSubnetMask(const IPv4Address& subnetMask);
857
858
    /// @return The default gateway IP address to force on the device
859
    IPv4Address getGatewayIpAddress() const;
860
861
    /// Set the default gateway IP address to force on the device
862
    /// @param[in] gatewayIpAddress The default gateway IP address to set
863
    void setGatewayIpAddress(const IPv4Address& gatewayIpAddress);
864
865
    // Overridden methods
866
867
    /// @return The size of the GVCP header and the force IP command body
868
    size_t getHeaderLen() const override
869
0
    {
870
0
      return sizeof(gvcp_request_header) + sizeof(gvcp_forceip_body);
871
0
    }
872
873
    /// @struct SerializedFields
874
    /// Fields written by GvcpForceIpRequestLayer's serializeLayer(), in addition to
875
    /// GvcpRequestLayer::SerializedFields.
876
    struct SerializedFields : GvcpRequestLayer::SerializedFields
877
    {
878
      /// @return All field descriptors for GvcpForceIpRequestLayer
879
      static std::vector<FieldDescriptor> all()
880
0
      {
881
0
        auto result = GvcpRequestLayer::SerializedFields::all();
882
0
        std::initializer_list<FieldDescriptor> extra{ MacAddress, IpAddress, SubnetMask, GatewayIpAddress };
883
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
884
0
        return result;
885
0
      }
886
887
      /// @brief MAC address of the device to configure, as a string
888
      static const FieldDescriptor MacAddress;
889
890
      /// @brief IP address to force on the device, as a string
891
      static const FieldDescriptor IpAddress;
892
893
      /// @brief Subnet mask to force on the device, as a string
894
      static const FieldDescriptor SubnetMask;
895
896
      /// @brief Default gateway IP address to force on the device, as a string
897
      static const FieldDescriptor GatewayIpAddress;
898
899
      // cppcheck-suppress duplInheritedMember
900
      /// Maximum field ID used by GvcpForceIpRequestLayer
901
      static constexpr uint16_t MaxID = GvcpRequestLayer::SerializedFields::MaxID + 4;
902
    };
903
904
  protected:
905
    void serializeLayer(ObjectScope& serializer) const override;
906
907
  private:
908
#pragma pack(push, 1)
909
    /// GVCP force IP command body, see the spec "16.2 FORCEIP". The data is stored as big-endian.
910
    struct gvcp_forceip_body
911
    {
912
      /// Reserved
913
      uint8_t reserved[2];
914
      /// MAC address
915
      uint8_t macAddress[6];
916
      /// Reserved
917
      uint8_t reserved2[12];
918
      /// IP address
919
      uint32_t ipAddress;
920
      /// Reserved
921
      uint8_t reserved3[12];
922
      /// Subnet mask
923
      uint32_t subnetMask;
924
      /// Reserved
925
      uint8_t reserved4[12];
926
      /// Default gateway
927
      uint32_t gateway;
928
    };
929
#pragma pack(pop)
930
    static_assert(sizeof(gvcp_forceip_body) == 56, "gvcp_forceip_body size is not 56 bytes");
931
932
    gvcp_forceip_body* getGvcpForceIpBody() const
933
0
    {
934
0
      return reinterpret_cast<gvcp_forceip_body*>(m_Data + sizeof(gvcp_request_header));
935
0
    }
936
  };
937
938
  /// @class GvcpForceIpAcknowledgeLayer
939
  /// Represents a GVCP force IP acknowledge (FORCEIP_ACK)
940
  class GvcpForceIpAcknowledgeLayer : public GvcpAcknowledgeLayer
941
  {
942
  public:
943
    /// A constructor that creates the layer from an existing packet raw data
944
    /// @param[in] data A pointer to the raw data
945
    /// @param[in] dataLen Size of the data in bytes
946
    /// @param[in] prevLayer A pointer to the previous layer
947
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
948
    GvcpForceIpAcknowledgeLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
949
0
        : GvcpAcknowledgeLayer(data, dataLen, prevLayer, packet)
950
0
    {}
951
952
    /// A constructor that creates a new GVCP force IP acknowledge
953
    /// @param[in] status The response status, optional
954
    /// @param[in] ackId The acknowledge ID, optional
955
    explicit GvcpForceIpAcknowledgeLayer(GvcpResponseStatus status = GvcpResponseStatus::Success,
956
                                         uint16_t ackId = 0)
957
        : GvcpAcknowledgeLayer(status, GvcpCommand::ForceIpAck, ackId)
958
0
    {}
959
  };
960
}  // namespace pcpp