/src/PcapPlusPlus/Packet++/header/ModbusLayer.h
Line | Count | Source |
1 | | #pragma once |
2 | | |
3 | | #include "Layer.h" |
4 | | |
5 | | /// @file |
6 | | /// This file contains classes for parsing, creating and editing Modbus packets. |
7 | | |
8 | | /// @namespace pcpp |
9 | | /// @brief The main namespace for the PcapPlusPlus lib |
10 | | namespace pcpp |
11 | | { |
12 | | |
13 | | #pragma pack(push, 1) |
14 | | /// @struct modbus_header |
15 | | /// MODBUS Application Protocol header |
16 | | struct modbus_header |
17 | | { |
18 | | /// For synchronization between messages of server and client |
19 | | uint16_t transactionId; |
20 | | /// 0 for Modbus/TCP |
21 | | uint16_t protocolId; |
22 | | /// Number of remaining bytes in this frame starting from the unit id |
23 | | uint16_t length; |
24 | | /// Unit identifier |
25 | | uint8_t unitId; |
26 | | /// Function code |
27 | | uint8_t functionCode; |
28 | | }; |
29 | | #pragma pack(pop) |
30 | | static_assert(sizeof(modbus_header) == 8, "modbus_header size is not 8 bytes"); |
31 | | |
32 | | /// @class ModbusLayer |
33 | | /// Represents the MODBUS Application Protocol layer |
34 | | class ModbusLayer : public Layer |
35 | | { |
36 | | public: |
37 | | /// @brief Enum class representing Modbus function codes. |
38 | | /// This enumeration defines the standard Modbus function codes used in request and response PDUs. |
39 | | /// Each value corresponds to a specific operation defined by the Modbus protocol. |
40 | | enum class ModbusFunctionCode : uint8_t |
41 | | { |
42 | | /// Read coil status (0x01) |
43 | | ReadCoils = 1, |
44 | | |
45 | | /// Read discrete input status (0x02) |
46 | | ReadDiscreteInputs = 2, |
47 | | |
48 | | /// Read holding registers (0x03) |
49 | | ReadHoldingRegisters = 3, |
50 | | |
51 | | /// Read input registers (0x04) |
52 | | ReadInputRegisters = 4, |
53 | | |
54 | | /// Write a single coil (0x05) |
55 | | WriteSingleCoil = 5, |
56 | | |
57 | | /// Write a single holding register (0x06) |
58 | | WriteSingleHoldingRegister = 6, |
59 | | |
60 | | /// Write multiple coils (0x0F) |
61 | | WriteMultipleCoils = 15, |
62 | | |
63 | | /// Write multiple holding registers (0x10) |
64 | | WriteMultipleHoldingRegisters = 16, |
65 | | |
66 | | /// Report slave ID (0x11) |
67 | | ReadSlaveId = 17, |
68 | | |
69 | | /// Unknown or unsupported function code (0xFF) |
70 | | UnknownFunction = 0xFF |
71 | | }; |
72 | | |
73 | | /// @struct ModbusReadInputRegisters |
74 | | /// Represents a Modbus request to read input registers. |
75 | | struct ModbusReadInputRegisters |
76 | | { |
77 | | uint16_t startingAddress; ///< Starting address of the input registers to read |
78 | | uint16_t quantity; ///< Number of input registers to read |
79 | | }; |
80 | | |
81 | | /// A constructor that creates the layer from an existing packet raw data |
82 | | /// @param[in] data A pointer to the raw data |
83 | | /// @param[in] dataLen Size of the data in bytes |
84 | | /// @param[in] prevLayer A pointer to the previous layer |
85 | | /// @param[in] packet A pointer to the Packet instance where layer will be stored in |
86 | | ModbusLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
87 | 0 | : Layer(data, dataLen, prevLayer, packet, Modbus) |
88 | 0 | {} |
89 | | |
90 | | /// A constructor that creates the layer from user inputs |
91 | | /// @param[in] transactionId Transaction ID |
92 | | /// @param[in] unitId Unit ID |
93 | | ModbusLayer(uint16_t transactionId, uint8_t unitId); |
94 | | |
95 | | /// @brief Check if a port is a valid MODBUS port |
96 | | /// @param port Port number to check |
97 | | /// @note MODBUS uses port 502, so this function checks if the port is equal to 502 |
98 | | /// @return true if the port is valid, false otherwise |
99 | | static bool isModbusPort(uint16_t port) |
100 | 60.0k | { |
101 | 60.0k | return port == 502; |
102 | 60.0k | } |
103 | | |
104 | | /// @return MODBUS message type |
105 | | uint16_t getTransactionId() const; |
106 | | |
107 | | /// @return MODBUS protocol id |
108 | | uint16_t getProtocolId() const; |
109 | | |
110 | | /// @return MODBUS remaining bytes in frame starting from the unit id |
111 | | /// @note This is the length of the MODBUS payload + unit_id, not the entire packet |
112 | | uint16_t getLength() const; |
113 | | |
114 | | /// @return MODBUS unit id |
115 | | uint8_t getUnitId() const; |
116 | | |
117 | | /// @return MODBUS function code |
118 | | ModbusFunctionCode getFunctionCode() const; |
119 | | |
120 | | /// @brief set the MODBUS transaction id |
121 | | /// @param transactionId transaction id |
122 | | void setTransactionId(uint16_t transactionId); |
123 | | |
124 | | /// @brief set the MODBUS header unit id |
125 | | /// @param unitId unit id |
126 | | void setUnitId(uint8_t unitId); |
127 | | |
128 | | /// @brief set the MODBUS header function code |
129 | | /// @param functionCode function code |
130 | | void setFunctionCode(ModbusFunctionCode functionCode); |
131 | | |
132 | | // Overridden methods |
133 | | |
134 | | /// Does nothing for this layer (ModbusLayer is always last) |
135 | | void parseNextLayer() override |
136 | 0 | {} |
137 | | |
138 | | /// @brief Get the length of the MODBUS header |
139 | | /// @return Length of the MODBUS header in bytes |
140 | | size_t getHeaderLen() const override |
141 | 0 | { |
142 | 0 | return sizeof(modbus_header); |
143 | 0 | } |
144 | | |
145 | | /// Does nothing for this layer |
146 | | void computeCalculateFields() override |
147 | 0 | {} |
148 | | |
149 | | /// @return A string representation of the layer most important data (should look like the layer description in |
150 | | /// Wireshark) |
151 | | std::string toString() const override; |
152 | | |
153 | | /// @return The OSI Model layer this protocol belongs to |
154 | | OsiModelLayer getOsiModelLayer() const override |
155 | 0 | { |
156 | 0 | return OsiModelApplicationLayer; |
157 | 0 | } |
158 | | |
159 | | private: |
160 | | /// @return A pointer to the MODBUS header |
161 | | modbus_header* getModbusHeader() const; |
162 | | }; |
163 | | |
164 | | } // namespace pcpp |