Coverage Report

Created: 2026-02-14 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/ModbusLayer.cpp
Line
Count
Source
1
#include "ModbusLayer.h"
2
#include "EndianPortable.h"
3
#include <iostream>
4
#include <iomanip>
5
#include <cstring>
6
#include "Logger.h"
7
8
namespace pcpp
9
{
10
  ModbusLayer::ModbusLayer(uint16_t transactionId, uint8_t unitId)
11
0
  {
12
0
    const int16_t pduSize = sizeof(ModbusReadInputRegisters);  // Currently only supporting Read Input Registers
13
0
    const size_t headerLen = sizeof(modbus_header);
14
15
0
    m_DataLen = headerLen + pduSize;
16
0
    m_Data = new uint8_t[m_DataLen]{};
17
0
    memset(m_Data, 0, m_DataLen);
18
19
    // Initialize the header fields to default values
20
0
    modbus_header* header = getModbusHeader();
21
0
    header->transactionId = htobe16(transactionId);
22
0
    header->protocolId = 0;                 // 0 for Modbus/TCP
23
0
    header->length = htobe16(pduSize + 2);  // Length includes unitId and functionCode
24
0
    header->unitId = unitId;
25
0
    header->functionCode = static_cast<uint8_t>(ModbusFunctionCode::ReadInputRegisters);
26
0
  }
27
28
  modbus_header* ModbusLayer::getModbusHeader() const
29
3.69k
  {
30
3.69k
    return reinterpret_cast<modbus_header*>(m_Data);
31
3.69k
  }
32
33
  uint16_t ModbusLayer::getTransactionId() const
34
738
  {
35
738
    return be16toh(getModbusHeader()->transactionId);
36
738
  }
37
38
  uint16_t ModbusLayer::getProtocolId() const
39
738
  {
40
738
    return be16toh(getModbusHeader()->protocolId);
41
738
  }
42
43
  uint16_t ModbusLayer::getLength() const
44
738
  {
45
738
    return be16toh(getModbusHeader()->length);
46
738
  }
47
48
  uint8_t ModbusLayer::getUnitId() const
49
738
  {
50
738
    return getModbusHeader()->unitId;
51
738
  }
52
53
  ModbusLayer::ModbusFunctionCode ModbusLayer::getFunctionCode() const
54
738
  {
55
738
    switch (getModbusHeader()->functionCode)
56
738
    {
57
122
    case 1:
58
122
      return ModbusFunctionCode::ReadCoils;
59
2
    case 2:
60
2
      return ModbusFunctionCode::ReadDiscreteInputs;
61
158
    case 3:
62
158
      return ModbusFunctionCode::ReadHoldingRegisters;
63
2
    case 4:
64
2
      return ModbusFunctionCode::ReadInputRegisters;
65
0
    case 5:
66
0
      return ModbusFunctionCode::WriteSingleCoil;
67
84
    case 6:
68
84
      return ModbusFunctionCode::WriteSingleHoldingRegister;
69
0
    case 15:
70
0
      return ModbusFunctionCode::WriteMultipleCoils;
71
2
    case 16:
72
2
      return ModbusFunctionCode::WriteMultipleHoldingRegisters;
73
0
    case 17:
74
0
      return ModbusFunctionCode::ReadSlaveId;
75
368
    default:
76
368
      return ModbusFunctionCode::UnknownFunction;
77
738
    }
78
738
  }
79
80
  void ModbusLayer::setTransactionId(uint16_t transactionId)
81
0
  {
82
0
    getModbusHeader()->transactionId = htobe16(transactionId);
83
0
  }
84
85
  void ModbusLayer::setUnitId(uint8_t unitId)
86
0
  {
87
0
    getModbusHeader()->unitId = unitId;
88
0
  }
89
90
  void ModbusLayer::setFunctionCode(ModbusLayer::ModbusFunctionCode functionCode)
91
0
  {
92
0
    getModbusHeader()->functionCode = static_cast<uint8_t>(functionCode);
93
0
  }
94
95
  std::string ModbusLayer::toString() const
96
738
  {
97
738
    return "Modbus Layer, Transaction ID: " + std::to_string(getTransactionId()) +
98
738
           ", Protocol ID: " + std::to_string(getProtocolId()) + ", Length: " + std::to_string(getLength()) +
99
738
           ", Unit ID: " + std::to_string(getUnitId()) +
100
738
           ", Function Code: " + std::to_string(static_cast<uint8_t>(getFunctionCode()));
101
738
  }
102
}  // namespace pcpp