/src/PcapPlusPlus/Packet++/src/S7CommLayer.cpp
Line | Count | Source |
1 | 0 | #define LOG_MODULE PacketLogModuleS7CommLayer |
2 | | |
3 | | #include "EndianPortable.h" |
4 | | |
5 | | #include "Logger.h" |
6 | | #include "S7CommLayer.h" |
7 | | #include <algorithm> |
8 | | #include <iostream> |
9 | | #include <cstring> |
10 | | #include <sstream> |
11 | | #include <stdexcept> |
12 | | |
13 | | namespace pcpp |
14 | | { |
15 | | |
16 | | S7CommLayer::S7CommLayer(uint8_t msgType, uint16_t pduRef, uint16_t paramLength, uint16_t dataLength, |
17 | | uint8_t errorClass, uint8_t errorCode) |
18 | 0 | { |
19 | 0 | size_t basicHeaderLen = msgType == 0x03 ? sizeof(s7comm_ack_data_hdr) : sizeof(s7commhdr); |
20 | 0 | size_t headerLen = basicHeaderLen + paramLength + dataLength; |
21 | 0 | allocData(headerLen); |
22 | |
|
23 | 0 | if (msgType == 0x03) |
24 | 0 | { |
25 | 0 | auto* ack_d = reinterpret_cast<s7comm_ack_data_hdr*>(m_Data); |
26 | 0 | ack_d->protocolId = 0x32; |
27 | 0 | ack_d->msgType = msgType; |
28 | 0 | ack_d->reserved = 0x0000; |
29 | 0 | ack_d->pduRef = htobe16(pduRef); |
30 | 0 | ack_d->paramLength = htobe16(paramLength); |
31 | 0 | ack_d->dataLength = htobe16(dataLength); |
32 | 0 | ack_d->errorClass = errorClass; |
33 | 0 | ack_d->errorCode = errorCode; |
34 | 0 | } |
35 | 0 | else |
36 | 0 | { |
37 | 0 | auto* s7commHdr = reinterpret_cast<s7commhdr*>(m_Data); |
38 | 0 | s7commHdr->protocolId = 0x32; |
39 | 0 | s7commHdr->msgType = msgType; |
40 | 0 | s7commHdr->reserved = 0x0000; |
41 | 0 | s7commHdr->pduRef = htobe16(pduRef); |
42 | 0 | s7commHdr->paramLength = htobe16(paramLength); |
43 | 0 | s7commHdr->dataLength = htobe16(dataLength); |
44 | 0 | } |
45 | |
|
46 | 0 | m_Parameter = nullptr; |
47 | 0 | m_Protocol = S7COMM; |
48 | 0 | } |
49 | | |
50 | | std::string S7CommLayer::toString() const |
51 | 4.95k | { |
52 | 4.95k | std::ostringstream str; |
53 | 4.95k | str << "S7Comm Layer, "; |
54 | | |
55 | 4.95k | switch (getS7commHeader()->msgType) |
56 | 4.95k | { |
57 | 1.15k | case 0x01: |
58 | 1.15k | str << "Job Request"; |
59 | 1.15k | break; |
60 | 12 | case 0x02: |
61 | 12 | str << "Ack"; |
62 | 12 | break; |
63 | 912 | case 0x03: |
64 | 912 | str << "Ack-Data"; |
65 | 912 | break; |
66 | 2.05k | case 0x07: |
67 | 2.05k | str << "Userdata"; |
68 | 2.05k | break; |
69 | 828 | default: |
70 | 828 | str << "Unknown message"; |
71 | 4.95k | } |
72 | | |
73 | 4.95k | return str.str(); |
74 | 4.95k | } |
75 | | |
76 | | static constexpr const char* msgTypeToString(uint8_t msgType) |
77 | 0 | { |
78 | 0 | switch (msgType) |
79 | 0 | { |
80 | 0 | case 0x01: |
81 | 0 | return "JobRequest"; |
82 | 0 | case 0x02: |
83 | 0 | return "Ack"; |
84 | 0 | case 0x03: |
85 | 0 | return "AckData"; |
86 | 0 | case 0x07: |
87 | 0 | return "Userdata"; |
88 | 0 | default: |
89 | 0 | return "Unknown"; |
90 | 0 | } |
91 | 0 | } |
92 | | |
93 | | const FieldDescriptor S7CommLayer::SerializedFields::MsgType{ Layer::SerializedFields::MaxID + 1, "msgType" }; |
94 | | const FieldDescriptor S7CommLayer::SerializedFields::MsgTypeName{ Layer::SerializedFields::MaxID + 2, |
95 | | "msgTypeName" }; |
96 | | const FieldDescriptor S7CommLayer::SerializedFields::PduRef{ Layer::SerializedFields::MaxID + 3, "pduRef" }; |
97 | | const FieldDescriptor S7CommLayer::SerializedFields::ParamLength{ Layer::SerializedFields::MaxID + 4, |
98 | | "paramLength" }; |
99 | | const FieldDescriptor S7CommLayer::SerializedFields::DataLength{ Layer::SerializedFields::MaxID + 5, "dataLength" }; |
100 | | const FieldDescriptor S7CommLayer::SerializedFields::ErrorClass{ Layer::SerializedFields::MaxID + 6, "errorClass" }; |
101 | | const FieldDescriptor S7CommLayer::SerializedFields::ErrorCode{ Layer::SerializedFields::MaxID + 7, "errorCode" }; |
102 | | |
103 | | void S7CommLayer::serializeLayer(ObjectScope& serializer) const |
104 | 0 | { |
105 | 0 | serializer.writeField(SerializedFields::MsgType, getMsgType()); |
106 | 0 | serializer.writeField(SerializedFields::MsgTypeName, msgTypeToString(getMsgType())); |
107 | 0 | serializer.writeField(SerializedFields::PduRef, getPduRef()); |
108 | 0 | serializer.writeField(SerializedFields::ParamLength, getParamLength()); |
109 | 0 | serializer.writeField(SerializedFields::DataLength, getDataLength()); |
110 | |
|
111 | 0 | auto* ackDataHeader = getS7commAckDataHeader(); |
112 | 0 | if (ackDataHeader != nullptr) |
113 | 0 | { |
114 | 0 | serializer.writeField(SerializedFields::ErrorClass, ackDataHeader->errorClass); |
115 | 0 | serializer.writeField(SerializedFields::ErrorCode, ackDataHeader->errorCode); |
116 | 0 | } |
117 | 0 | } |
118 | | |
119 | | bool S7CommLayer::isDataValid(const uint8_t* data, size_t dataSize) |
120 | 20.2k | { |
121 | 20.2k | if (!data || dataSize < sizeof(s7commhdr)) |
122 | 464 | return false; |
123 | | |
124 | 19.8k | return data[0] == 0x32; |
125 | 20.2k | } |
126 | | |
127 | | uint8_t S7CommLayer::getProtocolId() const |
128 | 0 | { |
129 | 0 | return getS7commHeader()->protocolId; |
130 | 0 | } |
131 | | |
132 | | uint8_t S7CommLayer::getMsgType() const |
133 | 0 | { |
134 | 0 | return getS7commHeader()->msgType; |
135 | 0 | } |
136 | | |
137 | | uint16_t S7CommLayer::getParamLength() const |
138 | 0 | { |
139 | 0 | return be16toh(getS7commHeader()->paramLength); |
140 | 0 | } |
141 | | |
142 | | uint16_t S7CommLayer::getPduRef() const |
143 | 0 | { |
144 | 0 | return be16toh(getS7commHeader()->pduRef); |
145 | 0 | } |
146 | | |
147 | | uint16_t S7CommLayer::getDataLength() const |
148 | 0 | { |
149 | 0 | return be16toh(getS7commHeader()->dataLength); |
150 | 0 | } |
151 | | |
152 | | void S7CommLayer::setMsgType(uint8_t msgType) const |
153 | 0 | { |
154 | 0 | getS7commHeader()->msgType = msgType; |
155 | 0 | } |
156 | | |
157 | | uint8_t S7CommLayer::getErrorCode() const |
158 | 0 | { |
159 | 0 | auto* ackDataHeader = getS7commAckDataHeader(); |
160 | 0 | if (ackDataHeader == nullptr) |
161 | 0 | { |
162 | 0 | throw std::runtime_error("Error code field not present!"); |
163 | 0 | } |
164 | | |
165 | 0 | return ackDataHeader->errorCode; |
166 | 0 | } |
167 | | |
168 | | uint8_t S7CommLayer::getErrorClass() const |
169 | 0 | { |
170 | 0 | auto* ackDataHeader = getS7commAckDataHeader(); |
171 | 0 | if (ackDataHeader == nullptr) |
172 | 0 | { |
173 | 0 | throw std::runtime_error("Error class field not present!"); |
174 | 0 | } |
175 | | |
176 | 0 | return ackDataHeader->errorClass; |
177 | 0 | } |
178 | | |
179 | | void S7CommLayer::setPduRef(uint16_t pduRef) const |
180 | 0 | { |
181 | 0 | getS7commHeader()->pduRef = htobe16(pduRef); |
182 | 0 | } |
183 | | |
184 | | void S7CommLayer::setErrorCode(uint8_t errorCode) const |
185 | 0 | { |
186 | 0 | auto* ackDataHeader = getS7commAckDataHeader(); |
187 | 0 | if (ackDataHeader == nullptr) |
188 | 0 | { |
189 | 0 | PCPP_LOG_ERROR("Cannot set the error code, the layer has no Ack-Data header"); |
190 | 0 | return; |
191 | 0 | } |
192 | | |
193 | 0 | ackDataHeader->errorCode = errorCode; |
194 | 0 | } |
195 | | |
196 | | void S7CommLayer::setErrorClass(uint8_t errorClass) const |
197 | 0 | { |
198 | 0 | auto* ackDataHeader = getS7commAckDataHeader(); |
199 | 0 | if (ackDataHeader == nullptr) |
200 | 0 | { |
201 | 0 | PCPP_LOG_ERROR("Cannot set the error class, the layer has no Ack-Data header"); |
202 | 0 | return; |
203 | 0 | } |
204 | | |
205 | 0 | ackDataHeader->errorClass = errorClass; |
206 | 0 | } |
207 | | |
208 | | const S7CommParameter* S7CommLayer::getParameter() |
209 | 0 | { |
210 | 0 | if (!m_Parameter) |
211 | 0 | { |
212 | | // the parameter length comes from the packet, so keep it inside the layer |
213 | 0 | size_t offset = std::min(getS7commHeaderLength(), m_DataLen); |
214 | 0 | size_t paramLength = std::min(static_cast<size_t>(getParamLength()), m_DataLen - offset); |
215 | 0 | m_Parameter = std::unique_ptr<S7CommParameter>(new S7CommParameter(m_Data + offset, paramLength)); |
216 | 0 | } |
217 | |
|
218 | 0 | return m_Parameter.get(); |
219 | 0 | } |
220 | | |
221 | | size_t S7CommLayer::getS7commHeaderLength() const |
222 | 0 | { |
223 | 0 | if (getS7commHeader()->msgType == 0x03) |
224 | 0 | { |
225 | 0 | return sizeof(s7comm_ack_data_hdr); |
226 | 0 | } |
227 | 0 | return sizeof(s7commhdr); |
228 | 0 | } |
229 | | |
230 | | } // namespace pcpp |