Coverage Report

Created: 2025-08-29 07:34

/src/PcapPlusPlus/Packet++/src/DoIpLayer.cpp
Line
Count
Source (jump to first uncovered line)
1
0
#define LOG_MODULE PacketLogModuleDoIpLayer
2
3
#include <unordered_map>
4
#include <sstream>
5
#include <iomanip>
6
#include "DoIpLayer.h"
7
#include "GeneralUtils.h"
8
#include "PayloadLayer.h"
9
#include "EndianPortable.h"
10
11
namespace pcpp
12
{
13
14
  // This unordered map provides human-readable descriptions for each activation type
15
  // defined in the DoIP protocol as per ISO 13400. It maps the `DoIpActivationTypes` enum values
16
  // to their corresponding descriptions.
17
  static const std::unordered_map<DoIpActivationTypes, std::string> DoIpEnumToStringActivationTypes{
18
    { DoIpActivationTypes::DEFAULT,          "Default"          },
19
    { DoIpActivationTypes::WWH_OBD,          "WWH-OBD"          },
20
    { DoIpActivationTypes::CENTRAL_SECURITY, "Central security" },
21
    { DoIpActivationTypes::UNKNOWN,          "Unknown"          },
22
  };
23
24
  // This unordered map provides human-readable descriptions for each Nack code related to
25
  // the DoIP Generic Header as per ISO 13400. It maps the `DoIpGenericHeaderNackCodes` enum
26
  // values to their corresponding descriptions.
27
  static const std::unordered_map<DoIpGenericHeaderNackCodes, std::string> DoIpEnumToStringGenericHeaderNackCodes{
28
    { DoIpGenericHeaderNackCodes::INCORRECT_PATTERN,      "Incorrect pattern format" },
29
    { DoIpGenericHeaderNackCodes::UNKNOWN_PAYLOAD_TYPE,   "Unknown payload type"     },
30
    { DoIpGenericHeaderNackCodes::INVALID_PAYLOAD_LENGTH, "Invalid payload length"   },
31
    { DoIpGenericHeaderNackCodes::MESSAGE_TOO_LARGE,      "Message too large"        },
32
    { DoIpGenericHeaderNackCodes::OUT_OF_MEMORY,          "Out of memory"            },
33
    { DoIpGenericHeaderNackCodes::UNKNOWN,                "Unknown"                  }
34
  };
35
36
  // This unordered map provides human-readable descriptions for each action code related to
37
  // the DoIP announcement message, as per ISO 13400. It maps the `DoIpActionCodes` enum
38
  // values to their corresponding descriptions.
39
  static const std::unordered_map<DoIpActionCodes, std::string> DoIpEnumToStringActionCodes{
40
    { DoIpActionCodes::NO_FURTHER_ACTION_REQUIRED,  "No further action required"                               },
41
    { DoIpActionCodes::RESERVED_ISO_0x01,           "Reserved by ISO 13400"                                    },
42
    { DoIpActionCodes::RESERVED_ISO_0x02,           "Reserved by ISO 13400"                                    },
43
    { DoIpActionCodes::RESERVED_ISO_0x03,           "Reserved by ISO 13400"                                    },
44
    { DoIpActionCodes::RESERVED_ISO_0x04,           "Reserved by ISO 13400"                                    },
45
    { DoIpActionCodes::RESERVED_ISO_0x05,           "Reserved by ISO 13400"                                    },
46
    { DoIpActionCodes::RESERVED_ISO_0x06,           "Reserved by ISO 13400"                                    },
47
    { DoIpActionCodes::RESERVED_ISO_0x07,           "Reserved by ISO 13400"                                    },
48
    { DoIpActionCodes::RESERVED_ISO_0x08,           "Reserved by ISO 13400"                                    },
49
    { DoIpActionCodes::RESERVED_ISO_0x09,           "Reserved by ISO 13400"                                    },
50
    { DoIpActionCodes::RESERVED_ISO_0x0A,           "Reserved by ISO 13400"                                    },
51
    { DoIpActionCodes::RESERVED_ISO_0x0B,           "Reserved by ISO 13400"                                    },
52
    { DoIpActionCodes::RESERVED_ISO_0x0C,           "Reserved by ISO 13400"                                    },
53
    { DoIpActionCodes::RESERVED_ISO_0x0D,           "Reserved by ISO 13400"                                    },
54
    { DoIpActionCodes::RESERVED_ISO_0x0E,           "Reserved by ISO 13400"                                    },
55
    { DoIpActionCodes::RESERVED_ISO_0x0F,           "Reserved by ISO 13400"                                    },
56
    { DoIpActionCodes::ROUTING_ACTIVATION_REQUIRED, "Routing activation required to initiate central security" },
57
    { DoIpActionCodes::UNKNOWN,                     "Unknown"                                             }
58
  };
59
60
  // This unordered map provides human-readable descriptions for each routing response code
61
  // related to the DoIP routing activation process, as per ISO 13400. It maps the `DoIpRoutingResponseCodes`
62
  // enum values to their corresponding descriptions.
63
  static const std::unordered_map<DoIpRoutingResponseCodes, std::string> DoIpEnumToStringRoutingResponseCodes{
64
    { DoIpRoutingResponseCodes::UNKNOWN_SOURCE_ADDRESS,            "Routing activation denied due to unknown source address"                   },
65
    { DoIpRoutingResponseCodes::NO_FREE_SOCKET,
66
         "Routing activation denied because all concurrently supported TCP_DATA sockets are registered and active"                                 },
67
    { DoIpRoutingResponseCodes::WRONG_SOURCE_ADDRESS,
68
         "Routing activation denied because an SA different from the table connection entry was received on the already activated TCP_DATA socket" },
69
    { DoIpRoutingResponseCodes::SOURCE_ADDRESS_ALREADY_REGISTERED,
70
         "Routing activation denied because the SA is already registered and active on a different TCP_DATA socket"                                },
71
    { DoIpRoutingResponseCodes::MISSING_AUTHENTICATION,            "Routing activation denied due to missing authentication"                   },
72
    { DoIpRoutingResponseCodes::REJECTED_CONFIRMATION,             "Routing activation denied due to rejected confirmation"                    },
73
    { DoIpRoutingResponseCodes::UNSUPPORTED_ACTIVATION_TYPE,
74
         "Routing activation denied due to unsupported routing activation type"                                                                    },
75
    { DoIpRoutingResponseCodes::ENCRYPTED_CONNECTION_TLS,
76
         "Routing activation denied due to request for encrypted connection via TLS"                                                               },
77
    { DoIpRoutingResponseCodes::RESERVED_ISO_0x08,                 "Reserved by ISO 13400"                                                     },
78
    { DoIpRoutingResponseCodes::RESERVED_ISO_0x09,                 "Reserved by ISO 13400"                                                     },
79
    { DoIpRoutingResponseCodes::RESERVED_ISO_0x0A,                 "Reserved by ISO 13400"                                                     },
80
    { DoIpRoutingResponseCodes::RESERVED_ISO_0x0B,                 "Reserved by ISO 13400"                                                     },
81
    { DoIpRoutingResponseCodes::RESERVED_ISO_0x0C,                 "Reserved by ISO 13400"                                                     },
82
    { DoIpRoutingResponseCodes::RESERVED_ISO_0x0D,                 "Reserved by ISO 13400"                                                     },
83
    { DoIpRoutingResponseCodes::RESERVED_ISO_0x0E,                 "Reserved by ISO 13400"                                                     },
84
    { DoIpRoutingResponseCodes::RESERVED_ISO_0x0F,                 "Reserved by ISO 13400"                                                     },
85
    { DoIpRoutingResponseCodes::ROUTING_SUCCESSFULLY_ACTIVATED,    "Routing successfully activated"                                            },
86
    { DoIpRoutingResponseCodes::CONFIRMATION_REQUIRED,             "Routing will be activated; confirmation required"                          },
87
    { DoIpRoutingResponseCodes::UNKNOWN,                           "Unknown"                                                               }
88
  };
89
90
  // This unordered map provides human-readable descriptions for each NACK (negative acknowledgment) code
91
  // related to DoIP diagnostic messages, as per ISO 13400. It maps the `DoIpDiagnosticMessageNackCodes` enum
92
  // values to their corresponding descriptions.
93
  static const std::unordered_map<DoIpDiagnosticMessageNackCodes, std::string> DoIpEnumToStringDiagnosticNackCodes{
94
    { DoIpDiagnosticMessageNackCodes::RESERVED_ISO_0x00,        "Reserved by ISO 13400"        },
95
    { DoIpDiagnosticMessageNackCodes::RESERVED_ISO_0x01,        "Reserved by ISO 13400"        },
96
    { DoIpDiagnosticMessageNackCodes::INVALID_SOURCE_ADDRESS,   "Invalid source address"       },
97
    { DoIpDiagnosticMessageNackCodes::INVALID_TARGET_ADDRESS,   "Unknown target address"       },
98
    { DoIpDiagnosticMessageNackCodes::MESSAGE_TOO_LARGE,        "Diagnostic message too large" },
99
    { DoIpDiagnosticMessageNackCodes::OUT_OF_MEMORY,            "Out of memory"                },
100
    { DoIpDiagnosticMessageNackCodes::TARGET_UNREACHABLE,       "Target unreachable"           },
101
    { DoIpDiagnosticMessageNackCodes::UNKNOWN_NETWORK,          "Unknown network"              },
102
    { DoIpDiagnosticMessageNackCodes::TRANSPORT_PROTOCOL_ERROR, "Transport protocol error"     },
103
    { DoIpDiagnosticMessageNackCodes::UNKNOWN,                  "Unknown"                      }
104
  };
105
106
  // This unordered map provides human-readable descriptions for each power mode code
107
  // related to DoIP diagnostics, as per ISO 13400. It maps the `DoIpDiagnosticPowerMode` enum
108
  // values to their corresponding descriptions.
109
  static const std::unordered_map<DoIpDiagnosticPowerModeCodes, std::string> DoIpEnumToStringDiagnosticPowerModeCodes{
110
    { DoIpDiagnosticPowerModeCodes::NOT_READY,     "Not ready"     },
111
    { DoIpDiagnosticPowerModeCodes::READY,         "Ready"         },
112
    { DoIpDiagnosticPowerModeCodes::NOT_SUPPORTED, "Not supported" },
113
    { DoIpDiagnosticPowerModeCodes::UNKNOWN,       "Unknown"       }
114
  };
115
116
  // This unordered map provides human-readable descriptions for the entity status codes
117
  // in the context of DoIP (Diagnostic over IP). It maps the `DoIpEntityStatus` enum values
118
  // to their corresponding descriptions, distinguishing between a "DoIP node" and a "DoIP gateway."
119
  static const std::unordered_map<DoIpEntityStatusResponseCode, std::string> DoIpEnumToStringEntityStatusNodeTypes{
120
    { DoIpEntityStatusResponseCode::NODE,    "DoIP node"    },
121
    { DoIpEntityStatusResponseCode::GATEWAY, "DoIP gateway" },
122
    { DoIpEntityStatusResponseCode::UNKNOWN, "Unknown"      }
123
  };
124
125
  // This unordered map provides a human-readable description for the DoIP acknowledgement
126
  // code `ACK`, which is used to confirm the successful reception or processing of a message.
127
  static const std::unordered_map<DoIpDiagnosticAckCodes, std::string> DoIpEnumToStringAckCode{
128
    { DoIpDiagnosticAckCodes::ACK,     "ACK"     },
129
        { DoIpDiagnosticAckCodes::UNKNOWN, "Unknown" }
130
  };
131
132
  // This unordered map provides a human-readable string for each synchronization status
133
  // defined in the `DoIpSyncStatus` enumeration. It is used to convert synchronization status
134
  // values to their respective descriptions for logging or display purposes.
135
  static const std::unordered_map<DoIpSyncStatus, std::string> DoIpEnumToStringSyncStatus{
136
    { DoIpSyncStatus::VIN_AND_OR_GID_ARE_SINCHRONIZED,     "VIN and/or GID are synchronized"     },
137
    { DoIpSyncStatus::RESERVED_ISO_0x01,                   "Reserved by ISO 13400"               },
138
    { DoIpSyncStatus::RESERVED_ISO_0x02,                   "Reserved by ISO 13400"               },
139
    { DoIpSyncStatus::RESERVED_ISO_0x03,                   "Reserved by ISO 13400"               },
140
    { DoIpSyncStatus::RESERVED_ISO_0x04,                   "Reserved by ISO 13400"               },
141
    { DoIpSyncStatus::RESERVED_ISO_0x05,                   "Reserved by ISO 13400"               },
142
    { DoIpSyncStatus::RESERVED_ISO_0x06,                   "Reserved by ISO 13400"               },
143
    { DoIpSyncStatus::RESERVED_ISO_0x07,                   "Reserved by ISO 13400"               },
144
    { DoIpSyncStatus::RESERVED_ISO_0x08,                   "Reserved by ISO 13400"               },
145
    { DoIpSyncStatus::RESERVED_ISO_0x09,                   "Reserved by ISO 13400"               },
146
    { DoIpSyncStatus::RESERVED_ISO_0x0A,                   "Reserved by ISO 13400"               },
147
    { DoIpSyncStatus::RESERVED_ISO_0x0B,                   "Reserved by ISO 13400"               },
148
    { DoIpSyncStatus::RESERVED_ISO_0x0C,                   "Reserved by ISO 13400"               },
149
    { DoIpSyncStatus::RESERVED_ISO_0x0D,                   "Reserved by ISO 13400"               },
150
    { DoIpSyncStatus::RESERVED_ISO_0x0E,                   "Reserved by ISO 13400"               },
151
    { DoIpSyncStatus::RESERVED_ISO_0x0F,                   "Reserved by ISO 13400"               },
152
    { DoIpSyncStatus::VIN_AND_OR_GID_ARE_NOT_SINCHRONIZED, "VIN and/or GID are not synchronized" },
153
    { DoIpSyncStatus::UNKNOWN,                             "Unknown"                             }
154
  };
155
156
  // This unordered map provides human-readable descriptions for each version of the
157
  // DoIP protocol as defined in ISO 13400. It maps the `DoIpProtocolVersion` enum values
158
  // to their corresponding descriptions.
159
  static const std::unordered_map<DoIpProtocolVersion, std::string> DoIpEnumToStringProtocolVersion{
160
    { DoIpProtocolVersion::DEFAULT_VALUE,      "Default value for vehicle identification request messages" },
161
    { DoIpProtocolVersion::ISO13400_2010,      "DoIP ISO/DIS 13400-2:2010"                                 },
162
    { DoIpProtocolVersion::ISO13400_2012,      "DoIP ISO 13400-2:2012"                                     },
163
    { DoIpProtocolVersion::ISO13400_2019,      "DoIP ISO 13400-2:2019"                                     },
164
    { DoIpProtocolVersion::ISO13400_2019_AMD1, "DoIP ISO 13400-2:2012 AMD1"                                },
165
    { DoIpProtocolVersion::RESERVED_VER,       "Reserved"                                                  },
166
    { DoIpProtocolVersion::UNKNOWN,            "Unknown Protocol Version"                                  },
167
  };
168
169
  // This unordered map provides human-readable descriptions for each payload type
170
  // defined in the DoIP protocol as per ISO 13400. It maps the `DoIpPayloadTypes` enum values
171
  // to their corresponding descriptions.
172
  static const std::unordered_map<DoIpPayloadTypes, std::string> DoIpEnumToStringPayloadType{
173
    { DoIpPayloadTypes::GENERIC_HEADER_NACK,                     "Generic DOIP header Nack"                   },
174
    { DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST,          "Vehicle identification request"             },
175
    { DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_EID, "Vehicle identification request with EID"    },
176
    { DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_VIN, "Vehicle identification request with VIN"    },
177
    { DoIpPayloadTypes::VEHICLE_ANNOUNCEMENT_MESSAGE,
178
         "Vehicle announcement message / vehicle identification response message"                                 },
179
    { DoIpPayloadTypes::ROUTING_ACTIVATION_REQUEST,              "Routing activation request"                 },
180
    { DoIpPayloadTypes::ROUTING_ACTIVATION_RESPONSE,             "Routing activation response"                },
181
    { DoIpPayloadTypes::ALIVE_CHECK_REQUEST,                     "Alive check request"                        },
182
    { DoIpPayloadTypes::ALIVE_CHECK_RESPONSE,                    "Alive check response"                       },
183
    { DoIpPayloadTypes::ENTITY_STATUS_REQUEST,                   "DOIP entity status request"                 },
184
    { DoIpPayloadTypes::ENTITY_STATUS_RESPONSE,                  "DOIP entity status response"                },
185
    { DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_REQUEST,           "Diagnostic power mode request information"  },
186
    { DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_RESPONSE,          "Diagnostic power mode response information" },
187
    { DoIpPayloadTypes::DIAGNOSTIC_MESSAGE,                      "Diagnostic message"                         },
188
    { DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_ACK,                  "Diagnostic message Ack"                     },
189
    { DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_NACK,                 "Diagnostic message Nack"                    }
190
  };
191
192
  DoIpLayer::DoIpLayer(size_t length)
193
0
  {
194
0
    m_DataLen = length;
195
0
    m_Protocol = DOIP;
196
0
    m_Data = new uint8_t[m_DataLen]{};
197
0
  }
198
199
  DoIpLayer::DoIpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
200
0
      : Layer(data, dataLen, prevLayer, packet, DOIP)
201
0
  {}
202
203
  bool DoIpLayer::isDataValid(uint8_t* data, size_t dataLen)
204
0
  {
205
0
    if (data == nullptr || dataLen < DOIP_HEADER_LEN)
206
0
      return false;
207
208
0
    auto* doipHeader = reinterpret_cast<doiphdr*>(data);
209
0
    const uint8_t version = doipHeader->protocolVersion;
210
0
    const uint8_t inVersion = doipHeader->invertProtocolVersion;
211
0
    const uint16_t payloadTypeRaw = doipHeader->payloadType;
212
0
    const uint32_t lengthRaw = doipHeader->payloadLength;
213
214
0
    if (!isPayloadTypeValid(be16toh(payloadTypeRaw)))
215
0
      return false;
216
    // if payload type is validated, we ensure passing a valid type to isProtocolVersionValid()
217
0
    const DoIpPayloadTypes payloadType = static_cast<DoIpPayloadTypes>(be16toh(payloadTypeRaw));
218
0
    if (!isProtocolVersionValid(version, inVersion, payloadType))
219
0
      return false;
220
221
0
    if (!isPayloadLengthValid(be32toh(lengthRaw), dataLen))
222
0
      return false;
223
224
0
    return true;
225
0
  }
226
227
  DoIpLayer* DoIpLayer::parseDoIpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
228
0
  {
229
0
    doiphdr* doipHeader = reinterpret_cast<doiphdr*>(data);
230
0
    uint16_t payloadType = doipHeader->payloadType;
231
0
    DoIpPayloadTypes detectedPayloadType = static_cast<DoIpPayloadTypes>(be16toh(payloadType));
232
233
0
    switch (detectedPayloadType)
234
0
    {
235
0
    case DoIpPayloadTypes::GENERIC_HEADER_NACK:
236
0
      return (DoIpGenericHeaderNack::isDataLenValid(dataLen))
237
0
                 ? new DoIpGenericHeaderNack(data, dataLen, prevLayer, packet)
238
0
                 : nullptr;
239
0
    case DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST:
240
0
      return (DoIpVehicleIdentificationRequest::isDataLenValid(dataLen))
241
0
                 ? new DoIpVehicleIdentificationRequest(data, dataLen, prevLayer, packet)
242
0
                 : nullptr;
243
0
    case DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_EID:
244
0
      return (DoIpVehicleIdentificationRequestWithEID::isDataLenValid(dataLen))
245
0
                 ? new DoIpVehicleIdentificationRequestWithEID(data, dataLen, prevLayer, packet)
246
0
                 : nullptr;
247
0
    case DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_VIN:
248
0
      return (DoIpVehicleIdentificationRequestWithVIN::isDataLenValid(dataLen))
249
0
                 ? new DoIpVehicleIdentificationRequestWithVIN(data, dataLen, prevLayer, packet)
250
0
                 : nullptr;
251
0
    case DoIpPayloadTypes::VEHICLE_ANNOUNCEMENT_MESSAGE:
252
0
      return (DoIpVehicleAnnouncementMessage::isDataLenValid(dataLen))
253
0
                 ? new DoIpVehicleAnnouncementMessage(data, dataLen, prevLayer, packet)
254
0
                 : nullptr;
255
0
    case DoIpPayloadTypes::ROUTING_ACTIVATION_REQUEST:
256
0
      return (DoIpRoutingActivationRequest::isDataLenValid(dataLen))
257
0
                 ? new DoIpRoutingActivationRequest(data, dataLen, prevLayer, packet)
258
0
                 : nullptr;
259
0
    case DoIpPayloadTypes::ROUTING_ACTIVATION_RESPONSE:
260
0
      return (DoIpRoutingActivationResponse::isDataLenValid(dataLen))
261
0
                 ? new DoIpRoutingActivationResponse(data, dataLen, prevLayer, packet)
262
0
                 : nullptr;
263
0
    case DoIpPayloadTypes::ALIVE_CHECK_REQUEST:
264
0
      return (DoIpAliveCheckRequest::isDataLenValid(dataLen))
265
0
                 ? new DoIpAliveCheckRequest(data, dataLen, prevLayer, packet)
266
0
                 : nullptr;
267
0
    case DoIpPayloadTypes::ALIVE_CHECK_RESPONSE:
268
0
      return (DoIpAliveCheckResponse::isDataLenValid(dataLen))
269
0
                 ? new DoIpAliveCheckResponse(data, dataLen, prevLayer, packet)
270
0
                 : nullptr;
271
0
    case DoIpPayloadTypes::ENTITY_STATUS_REQUEST:
272
0
      return (DoIpEntityStatusRequest::isDataLenValid(dataLen))
273
0
                 ? new DoIpEntityStatusRequest(data, dataLen, prevLayer, packet)
274
0
                 : nullptr;
275
0
    case DoIpPayloadTypes::ENTITY_STATUS_RESPONSE:
276
0
      return (DoIpEntityStatusResponse::isDataLenValid(dataLen))
277
0
                 ? new DoIpEntityStatusResponse(data, dataLen, prevLayer, packet)
278
0
                 : nullptr;
279
0
    case DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_REQUEST:
280
0
      return (DoIpDiagnosticPowerModeRequest::isDataLenValid(dataLen))
281
0
                 ? new DoIpDiagnosticPowerModeRequest(data, dataLen, prevLayer, packet)
282
0
                 : nullptr;
283
0
    case DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_RESPONSE:
284
0
      return (DoIpDiagnosticPowerModeResponse::isDataLenValid(dataLen))
285
0
                 ? new DoIpDiagnosticPowerModeResponse(data, dataLen, prevLayer, packet)
286
0
                 : nullptr;
287
0
    case DoIpPayloadTypes::DIAGNOSTIC_MESSAGE:
288
0
      return (DoIpDiagnosticMessage::isDataLenValid(dataLen))
289
0
                 ? new DoIpDiagnosticMessage(data, dataLen, prevLayer, packet)
290
0
                 : nullptr;
291
0
    case DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_ACK:
292
0
      return (DoIpDiagnosticMessageAck::isDataLenValid(dataLen))
293
0
                 ? new DoIpDiagnosticMessageAck(data, dataLen, prevLayer, packet)
294
0
                 : nullptr;
295
0
    case DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_NACK:
296
0
      return (DoIpDiagnosticMessageNack::isDataLenValid(dataLen))
297
0
                 ? new DoIpDiagnosticMessageNack(data, dataLen, prevLayer, packet)
298
0
                 : nullptr;
299
0
    default:
300
0
      return nullptr;
301
0
    }
302
0
  }
303
304
  DoIpProtocolVersion DoIpLayer::getProtocolVersion() const
305
0
  {
306
0
    uint8_t version = getDoIpHeader()->protocolVersion;
307
308
0
    switch (static_cast<DoIpProtocolVersion>(version))
309
0
    {
310
0
    case DoIpProtocolVersion::RESERVED_VER:
311
0
    case DoIpProtocolVersion::ISO13400_2010:
312
0
    case DoIpProtocolVersion::ISO13400_2012:
313
0
    case DoIpProtocolVersion::ISO13400_2019:
314
0
    case DoIpProtocolVersion::ISO13400_2019_AMD1:
315
0
    case DoIpProtocolVersion::DEFAULT_VALUE:
316
0
      return static_cast<DoIpProtocolVersion>(version);
317
318
0
    default:
319
0
      return DoIpProtocolVersion::UNKNOWN;
320
0
    }
321
0
  }
322
323
  std::string DoIpLayer::getProtocolVersionAsStr() const
324
0
  {
325
0
    return DoIpEnumToStringProtocolVersion.find(getProtocolVersion())->second;
326
0
  }
327
328
  void DoIpLayer::setProtocolVersion(DoIpProtocolVersion version)
329
0
  {
330
0
    getDoIpHeader()->protocolVersion = static_cast<uint8_t>(version);
331
0
  }
332
333
  void DoIpLayer::setProtocolVersion(uint8_t rawVersion)
334
0
  {
335
0
    getDoIpHeader()->protocolVersion = rawVersion;
336
0
  }
337
338
  uint8_t DoIpLayer::getInvertProtocolVersion() const
339
0
  {
340
0
    return getDoIpHeader()->invertProtocolVersion;
341
0
  }
342
343
  void DoIpLayer::setInvertProtocolVersion(uint8_t iVersion)
344
0
  {
345
0
    getDoIpHeader()->invertProtocolVersion = iVersion;
346
0
  }
347
348
  void DoIpLayer::setPayloadType(DoIpPayloadTypes type)
349
0
  {
350
0
    getDoIpHeader()->payloadType = htobe16(static_cast<uint16_t>(type));
351
0
  }
352
353
  std::string DoIpLayer::getPayloadTypeAsStr() const
354
0
  {
355
0
    auto it = DoIpEnumToStringPayloadType.find(getPayloadType());
356
0
    return (it != DoIpEnumToStringPayloadType.end()) ? it->second : "Unknown Payload Type";
357
0
  }
358
359
  uint32_t DoIpLayer::getPayloadLength() const
360
0
  {
361
0
    return be32toh(getDoIpHeader()->payloadLength);
362
0
  }
363
364
  void DoIpLayer::setPayloadLength(uint32_t payloadLength)
365
0
  {
366
0
    getDoIpHeader()->payloadLength = htobe32(payloadLength);
367
0
  }
368
369
  std::string DoIpLayer::toString() const
370
0
  {
371
0
    std::ostringstream oss;
372
0
    oss << "DoIP Layer, " << getPayloadTypeAsStr() << " (0x" << std::hex << std::setw(4) << std::setfill('0')
373
0
        << static_cast<uint16_t>(getPayloadType()) << ")";
374
0
    return oss.str();
375
0
  }
376
377
  void DoIpLayer::setHeaderFields(DoIpProtocolVersion version, DoIpPayloadTypes type, uint32_t length)
378
0
  {
379
0
    setProtocolVersion(version);
380
0
    setInvertProtocolVersion(~(static_cast<uint8_t>(version)));
381
0
    setPayloadType(type);
382
0
    setPayloadLength(length);
383
0
  }
384
385
  void DoIpLayer::parseNextLayer()
386
0
  {
387
0
    if (getPayloadType() == DoIpPayloadTypes::DIAGNOSTIC_MESSAGE)
388
0
    {
389
0
      size_t headerLen = getHeaderLen();
390
391
0
      if (m_DataLen <= headerLen)
392
0
      {
393
0
        return;
394
0
      }
395
396
0
      uint8_t* payload = m_Data + headerLen;
397
0
      size_t payloadLen = m_DataLen - headerLen;
398
399
0
      constructNextLayer<PayloadLayer>(payload, payloadLen, m_Packet);
400
0
    }
401
0
  }
402
403
  //~~~~~~~~~~~~~~~~~~~~~~|
404
  // DoIpGenericHeaderNack|
405
  //~~~~~~~~~~~~~~~~~~~~~~|
406
  DoIpGenericHeaderNack::DoIpGenericHeaderNack(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
407
0
      : DoIpLayer(data, dataLen, prevLayer, packet)
408
0
  {}
409
410
0
  DoIpGenericHeaderNack::DoIpGenericHeaderNack(DoIpGenericHeaderNackCodes nackCode) : DoIpLayer(FIXED_LEN)
411
0
  {
412
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, getPayloadType(), (FIXED_LEN - DOIP_HEADER_LEN));
413
0
    setNackCode(nackCode);
414
0
  }
415
416
  DoIpGenericHeaderNackCodes DoIpGenericHeaderNack::getNackCode() const
417
0
  {
418
0
    uint8_t nackCode = getGenericHeaderNack()->nackCode;
419
0
    if (nackCode <= static_cast<uint8_t>(DoIpGenericHeaderNackCodes::INVALID_PAYLOAD_LENGTH))
420
0
    {
421
0
      return static_cast<DoIpGenericHeaderNackCodes>(nackCode);
422
0
    }
423
0
    return DoIpGenericHeaderNackCodes::UNKNOWN;
424
0
  }
425
426
  void DoIpGenericHeaderNack::setNackCode(DoIpGenericHeaderNackCodes nackCode)
427
0
  {
428
0
    getGenericHeaderNack()->nackCode = static_cast<uint8_t>(nackCode);
429
0
  }
430
431
  std::string DoIpGenericHeaderNack::getSummary() const
432
0
  {
433
0
    std::ostringstream oss;
434
0
    DoIpGenericHeaderNackCodes nackCode = getNackCode();
435
0
    auto it = DoIpEnumToStringGenericHeaderNackCodes.find(nackCode);
436
0
    oss << "Generic header nack code: " << it->second << " (0x" << std::hex
437
0
        << static_cast<unsigned>(getGenericHeaderNack()->nackCode) << ")\n";
438
0
    return oss.str();
439
0
  }
440
441
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
442
  // DoIpVehicleIdentificationRequest|
443
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
444
0
  DoIpVehicleIdentificationRequest::DoIpVehicleIdentificationRequest() : DoIpLayer(DOIP_HEADER_LEN)
445
0
  {
446
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, getPayloadType(), 0);
447
0
  }
448
449
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
450
  // DoIpVehicleIdentificationRequestWithEID|
451
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
452
  DoIpVehicleIdentificationRequestWithEID::DoIpVehicleIdentificationRequestWithEID(uint8_t* data, size_t dataLen,
453
                                                                                   Layer* prevLayer, Packet* packet)
454
0
      : DoIpLayer(data, dataLen, prevLayer, packet)
455
0
  {}
456
457
  DoIpVehicleIdentificationRequestWithEID::DoIpVehicleIdentificationRequestWithEID(
458
      const std::array<uint8_t, DOIP_EID_LEN>& eid)
459
0
      : DoIpLayer(FIXED_LEN)
460
0
  {
461
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, getPayloadType(), DOIP_EID_LEN);
462
0
    setEID(eid);
463
0
  }
464
465
  std::array<uint8_t, DOIP_EID_LEN> DoIpVehicleIdentificationRequestWithEID::getEID() const
466
0
  {
467
0
    return getVehicleIdentificationRequestWEID()->eid;
468
0
  }
469
470
  void DoIpVehicleIdentificationRequestWithEID::setEID(const std::array<uint8_t, DOIP_EID_LEN>& eid)
471
0
  {
472
0
    getVehicleIdentificationRequestWEID()->eid = eid;
473
0
  }
474
475
  std::string DoIpVehicleIdentificationRequestWithEID::getSummary() const
476
0
  {
477
0
    std::ostringstream oss;
478
0
    oss << "EID: " << pcpp::byteArrayToHexString(getEID().data(), DOIP_EID_LEN) << "\n";
479
0
    return oss.str();
480
0
  }
481
482
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
483
  // DoIpVehicleIdentificationRequestWithVIN|
484
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
485
  DoIpVehicleIdentificationRequestWithVIN::DoIpVehicleIdentificationRequestWithVIN(uint8_t* data, size_t dataLen,
486
                                                                                   Layer* prevLayer, Packet* packet)
487
0
      : DoIpLayer(data, dataLen, prevLayer, packet)
488
0
  {}
489
490
  DoIpVehicleIdentificationRequestWithVIN::DoIpVehicleIdentificationRequestWithVIN(
491
      const std::array<uint8_t, DOIP_VIN_LEN>& vin)
492
0
      : DoIpLayer(FIXED_LEN)
493
0
  {
494
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, getPayloadType(), DOIP_VIN_LEN);
495
0
    setVIN(vin);
496
0
  }
497
498
  std::array<uint8_t, DOIP_VIN_LEN> DoIpVehicleIdentificationRequestWithVIN::getVIN() const
499
0
  {
500
0
    return getVehicleIdentificationRequestWVIN()->vin;
501
0
  }
502
503
  void DoIpVehicleIdentificationRequestWithVIN::setVIN(const std::array<uint8_t, DOIP_VIN_LEN>& vin)
504
0
  {
505
0
    getVehicleIdentificationRequestWVIN()->vin = vin;
506
0
  }
507
508
  std::string DoIpVehicleIdentificationRequestWithVIN::getSummary() const
509
0
  {
510
0
    std::ostringstream oss;
511
0
    oss << "VIN: " << std::string(reinterpret_cast<const char*>(getVIN().data()), DOIP_VIN_LEN) << "\n";
512
0
    return oss.str();
513
0
  }
514
515
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
516
  // DoIpVehicleAnnouncementMessage|
517
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
518
  DoIpVehicleAnnouncementMessage::DoIpVehicleAnnouncementMessage(uint8_t* data, size_t dataLen, Layer* prevLayer,
519
                                                                 Packet* packet)
520
0
      : DoIpLayer(data, dataLen, prevLayer, packet)
521
0
  {}
522
523
  DoIpVehicleAnnouncementMessage::DoIpVehicleAnnouncementMessage(const std::array<uint8_t, DOIP_VIN_LEN>& vin,
524
                                                                 uint16_t logicalAddress,
525
                                                                 const std::array<uint8_t, DOIP_EID_LEN>& eid,
526
                                                                 const std::array<uint8_t, DOIP_GID_LEN>& gid,
527
                                                                 DoIpActionCodes actionCode)
528
0
      : DoIpLayer(FIXED_LEN)
529
0
  {
530
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, getPayloadType(), (FIXED_LEN - DOIP_HEADER_LEN));
531
532
0
    setVIN(vin);
533
0
    setLogicalAddress(logicalAddress);
534
0
    setEID(eid);
535
0
    setGID(gid);
536
0
    setFurtherActionRequired(actionCode);
537
0
  }
538
539
  std::array<uint8_t, DOIP_VIN_LEN> DoIpVehicleAnnouncementMessage::getVIN() const
540
0
  {
541
0
    return getVehicleAnnouncementMessage()->vin;
542
0
  }
543
544
  void DoIpVehicleAnnouncementMessage::setVIN(const std::array<uint8_t, DOIP_VIN_LEN>& vin)
545
0
  {
546
0
    getVehicleAnnouncementMessage()->vin = vin;
547
0
  }
548
549
  uint16_t DoIpVehicleAnnouncementMessage::getLogicalAddress() const
550
0
  {
551
0
    return be16toh(getVehicleAnnouncementMessage()->logicalAddress);
552
0
  }
553
554
  void DoIpVehicleAnnouncementMessage::setLogicalAddress(uint16_t logicalAddress)
555
0
  {
556
0
    getVehicleAnnouncementMessage()->logicalAddress = htobe16(logicalAddress);
557
0
  }
558
559
  std::array<uint8_t, DOIP_EID_LEN> DoIpVehicleAnnouncementMessage::getEID() const
560
0
  {
561
0
    return getVehicleAnnouncementMessage()->eid;
562
0
  }
563
564
  void DoIpVehicleAnnouncementMessage::setEID(const std::array<uint8_t, DOIP_EID_LEN>& eid)
565
0
  {
566
0
    getVehicleAnnouncementMessage()->eid = eid;
567
0
  }
568
569
  std::array<uint8_t, DOIP_GID_LEN> DoIpVehicleAnnouncementMessage::getGID() const
570
0
  {
571
0
    return getVehicleAnnouncementMessage()->gid;
572
0
  }
573
574
  void DoIpVehicleAnnouncementMessage::setGID(const std::array<uint8_t, DOIP_GID_LEN>& gid)
575
0
  {
576
0
    getVehicleAnnouncementMessage()->gid = gid;
577
0
  }
578
579
  DoIpActionCodes DoIpVehicleAnnouncementMessage::getFurtherActionRequired() const
580
0
  {
581
0
    uint8_t actionCode = getVehicleAnnouncementMessage()->actionCode;
582
0
    if (actionCode <= static_cast<uint8_t>(DoIpActionCodes::ROUTING_ACTIVATION_REQUIRED))
583
0
    {
584
0
      return static_cast<DoIpActionCodes>(actionCode);
585
0
    }
586
0
    return DoIpActionCodes::UNKNOWN;
587
0
  }
588
589
  void DoIpVehicleAnnouncementMessage::setFurtherActionRequired(DoIpActionCodes action)
590
0
  {
591
0
    getVehicleAnnouncementMessage()->actionCode = static_cast<uint8_t>(action);
592
0
  }
593
594
  DoIpSyncStatus DoIpVehicleAnnouncementMessage::getSyncStatus() const
595
0
  {
596
0
    if (!hasSyncStatus())
597
0
      throw std::runtime_error("Sync status field not present!");
598
599
0
    uint8_t syncStatus = *(m_Data + SYNC_STATUS_OFFSET);
600
0
    if (syncStatus <= static_cast<uint8_t>(DoIpSyncStatus::VIN_AND_OR_GID_ARE_NOT_SINCHRONIZED))
601
0
      return static_cast<DoIpSyncStatus>(syncStatus);
602
603
0
    return DoIpSyncStatus::UNKNOWN;
604
0
  }
605
606
  void DoIpVehicleAnnouncementMessage::setSyncStatus(DoIpSyncStatus syncStatus)
607
0
  {
608
0
    if (!hasSyncStatus())
609
0
    {
610
0
      extendLayer(SYNC_STATUS_OFFSET, SYNC_STATUS_LEN);
611
0
    }
612
0
    setPayloadLength(OPT_LEN - DOIP_HEADER_LEN);
613
0
    *(m_Data + SYNC_STATUS_OFFSET) = static_cast<uint8_t>(syncStatus);
614
0
  }
615
616
  bool DoIpVehicleAnnouncementMessage::hasSyncStatus() const
617
0
  {
618
0
    return (m_DataLen == OPT_LEN);
619
0
  }
620
621
  void DoIpVehicleAnnouncementMessage::clearSyncStatus()
622
0
  {
623
0
    if (!hasSyncStatus())
624
0
    {
625
0
      PCPP_LOG_DEBUG("DoIP packet has no syncStatus!");
626
0
      return;
627
0
    }
628
0
    shortenLayer(SYNC_STATUS_OFFSET, SYNC_STATUS_LEN);
629
0
    setPayloadLength(FIXED_LEN - DOIP_HEADER_LEN);
630
0
  }
631
632
  std::string DoIpVehicleAnnouncementMessage::getSummary() const
633
0
  {
634
0
    std::ostringstream oss;
635
0
    oss << "VIN: " << std::string(reinterpret_cast<const char*>(getVIN().data()), DOIP_VIN_LEN) << "\n";
636
0
    oss << "Logical address: 0x" << std::hex << getLogicalAddress() << "\n";
637
0
    oss << "EID: " << pcpp::byteArrayToHexString(getEID().data(), DOIP_EID_LEN) << "\n";
638
0
    oss << "GID: " << pcpp::byteArrayToHexString(getGID().data(), DOIP_GID_LEN) << "\n";
639
640
0
    auto it = DoIpEnumToStringActionCodes.find(getFurtherActionRequired());
641
0
    oss << "Further action required: " << it->second << " (0x" << std::hex
642
0
        << static_cast<unsigned>(getVehicleAnnouncementMessage()->actionCode) << ")\n";
643
644
0
    if (hasSyncStatus())
645
0
    {
646
0
      auto syncStatus = getSyncStatus();
647
0
      auto itSync = DoIpEnumToStringSyncStatus.find(syncStatus);
648
0
      oss << "VIN/GID sync status: " << itSync->second << " (0x" << std::hex
649
0
          << static_cast<unsigned>(*(m_Data + SYNC_STATUS_OFFSET)) << ")\n";
650
0
    }
651
652
0
    return oss.str();
653
0
  }
654
655
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
656
  // DoIpRoutingActivationRequest|
657
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
658
  DoIpRoutingActivationRequest::DoIpRoutingActivationRequest(uint8_t* data, size_t dataLen, Layer* prevLayer,
659
                                                             Packet* packet)
660
0
      : DoIpLayer(data, dataLen, prevLayer, packet)
661
0
  {}
662
663
  DoIpRoutingActivationRequest::DoIpRoutingActivationRequest(uint16_t sourceAddress,
664
                                                             DoIpActivationTypes activationType)
665
0
      : DoIpLayer(FIXED_LEN)
666
0
  {
667
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, getPayloadType(), (FIXED_LEN - DOIP_HEADER_LEN));
668
669
0
    setSourceAddress(sourceAddress);
670
0
    setActivationType(activationType);
671
    // Reserved ISO is always all zeros
672
0
    setReservedIso({});
673
0
  }
674
675
  uint16_t DoIpRoutingActivationRequest::getSourceAddress() const
676
0
  {
677
0
    return be16toh(getRoutingActivationRequest()->sourceAddress);
678
0
  }
679
680
  void DoIpRoutingActivationRequest::setSourceAddress(uint16_t value)
681
0
  {
682
0
    getRoutingActivationRequest()->sourceAddress = htobe16(value);
683
0
  }
684
685
  DoIpActivationTypes DoIpRoutingActivationRequest::getActivationType() const
686
0
  {
687
0
    auto activationType = static_cast<DoIpActivationTypes>(getRoutingActivationRequest()->activationType);
688
0
    switch (activationType)
689
0
    {
690
0
    case DoIpActivationTypes::DEFAULT:
691
0
    case DoIpActivationTypes::WWH_OBD:
692
0
    case DoIpActivationTypes::CENTRAL_SECURITY:
693
0
      return activationType;
694
0
    default:
695
0
      return DoIpActivationTypes::UNKNOWN;
696
0
    }
697
0
  }
698
699
  void DoIpRoutingActivationRequest::setActivationType(DoIpActivationTypes activationType)
700
0
  {
701
0
    getRoutingActivationRequest()->activationType = static_cast<uint8_t>(activationType);
702
0
  }
703
704
  std::array<uint8_t, DOIP_RESERVED_ISO_LEN> DoIpRoutingActivationRequest::getReservedIso() const
705
0
  {
706
0
    return getRoutingActivationRequest()->reservedIso;
707
0
  }
708
709
  void DoIpRoutingActivationRequest::setReservedIso(const std::array<uint8_t, DOIP_RESERVED_ISO_LEN>& reservedIso)
710
0
  {
711
0
    getRoutingActivationRequest()->reservedIso = reservedIso;
712
0
  }
713
714
  std::array<uint8_t, DOIP_RESERVED_OEM_LEN> DoIpRoutingActivationRequest::getReservedOem() const
715
0
  {
716
0
    if (!hasReservedOem())
717
0
      throw std::runtime_error("Reserved OEM field not present!");
718
719
0
    std::array<uint8_t, DOIP_RESERVED_OEM_LEN> reservedOem;
720
0
    memcpy(reservedOem.data(), m_Data + RESERVED_OEM_OFFSET, DOIP_RESERVED_OEM_LEN);
721
0
    return reservedOem;
722
0
  }
723
724
  void DoIpRoutingActivationRequest::setReservedOem(const std::array<uint8_t, DOIP_RESERVED_OEM_LEN>& reservedOem)
725
0
  {
726
0
    if (!hasReservedOem())
727
0
    {
728
0
      extendLayer(RESERVED_OEM_OFFSET, DOIP_RESERVED_OEM_LEN);
729
0
    }
730
0
    setPayloadLength(OPT_LEN - DOIP_HEADER_LEN);
731
0
    memcpy((m_Data + RESERVED_OEM_OFFSET), reservedOem.data(), DOIP_RESERVED_OEM_LEN);
732
0
  }
733
734
  bool DoIpRoutingActivationRequest::hasReservedOem() const
735
0
  {
736
0
    return (m_DataLen == OPT_LEN);
737
0
  }
738
739
  void DoIpRoutingActivationRequest::clearReservedOem()
740
0
  {
741
0
    if (!hasReservedOem())
742
0
    {
743
0
      PCPP_LOG_DEBUG("DoIP packet has no reserved OEM field!");
744
0
      return;
745
0
    }
746
747
0
    shortenLayer(FIXED_LEN, DOIP_RESERVED_OEM_LEN);
748
0
    setPayloadLength(FIXED_LEN - DOIP_HEADER_LEN);
749
0
    PCPP_LOG_DEBUG("Reserved OEM field has been removed successfully!");
750
0
  }
751
752
  std::string DoIpRoutingActivationRequest::getSummary() const
753
0
  {
754
0
    std::ostringstream oss;
755
0
    oss << "Source Address: 0x" << std::hex << getSourceAddress() << "\n";
756
757
0
    auto it = DoIpEnumToStringActivationTypes.find(getActivationType());
758
0
    oss << "Activation type: " << it->second << " (0x" << std::hex
759
0
        << static_cast<unsigned>(getRoutingActivationRequest()->activationType) << ")\n";
760
761
0
    oss << "Reserved by ISO: " << pcpp::byteArrayToHexString(getReservedIso().data(), DOIP_RESERVED_ISO_LEN)
762
0
        << "\n";
763
0
    if (hasReservedOem())
764
0
      oss << "Reserved by OEM: " << pcpp::byteArrayToHexString(getReservedOem().data(), DOIP_RESERVED_OEM_LEN)
765
0
          << '\n';
766
767
0
    return oss.str();
768
0
  }
769
770
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
771
  // DoIpRoutingActivationResponse|
772
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
773
  DoIpRoutingActivationResponse::DoIpRoutingActivationResponse(uint8_t* data, size_t dataLen, Layer* prevLayer,
774
                                                               Packet* packet)
775
0
      : DoIpLayer(data, dataLen, prevLayer, packet)
776
0
  {}
777
778
  DoIpRoutingActivationResponse::DoIpRoutingActivationResponse(uint16_t logicalAddressExternalTester,
779
                                                               uint16_t sourceAddress,
780
                                                               DoIpRoutingResponseCodes responseCode)
781
0
      : DoIpLayer(FIXED_LEN)
782
0
  {
783
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, getPayloadType(), (FIXED_LEN - DOIP_HEADER_LEN));
784
785
0
    setLogicalAddressExternalTester(logicalAddressExternalTester);
786
0
    setSourceAddress(sourceAddress);
787
0
    setResponseCode(responseCode);
788
0
    setReservedIso({});
789
0
  }
790
791
  uint16_t DoIpRoutingActivationResponse::getLogicalAddressExternalTester() const
792
0
  {
793
0
    return be16toh(getRoutingActivationResponse()->logicalAddressExternalTester);
794
0
  }
795
796
  void DoIpRoutingActivationResponse::setLogicalAddressExternalTester(uint16_t addr)
797
0
  {
798
0
    getRoutingActivationResponse()->logicalAddressExternalTester = htobe16(addr);
799
0
  }
800
801
  uint16_t DoIpRoutingActivationResponse::getSourceAddress() const
802
0
  {
803
0
    return be16toh(getRoutingActivationResponse()->sourceAddress);
804
0
  }
805
806
  void DoIpRoutingActivationResponse::setSourceAddress(uint16_t sourceAddress)
807
0
  {
808
0
    getRoutingActivationResponse()->sourceAddress = htobe16(sourceAddress);
809
0
  }
810
811
  DoIpRoutingResponseCodes DoIpRoutingActivationResponse::getResponseCode() const
812
0
  {
813
0
    uint8_t code = getRoutingActivationResponse()->responseCode;
814
0
    if (code <= static_cast<uint8_t>(DoIpRoutingResponseCodes::CONFIRMATION_REQUIRED))
815
0
    {
816
0
      return static_cast<DoIpRoutingResponseCodes>(code);
817
0
    }
818
0
    return DoIpRoutingResponseCodes::UNKNOWN;
819
0
  }
820
821
  void DoIpRoutingActivationResponse::setResponseCode(DoIpRoutingResponseCodes code)
822
0
  {
823
0
    getRoutingActivationResponse()->responseCode = static_cast<uint8_t>(code);
824
0
  }
825
826
  std::array<uint8_t, DOIP_RESERVED_ISO_LEN> DoIpRoutingActivationResponse::getReservedIso() const
827
0
  {
828
0
    return getRoutingActivationResponse()->reservedIso;
829
0
  }
830
831
  void DoIpRoutingActivationResponse::setReservedIso(const std::array<uint8_t, DOIP_RESERVED_ISO_LEN>& reservedIso)
832
0
  {
833
0
    getRoutingActivationResponse()->reservedIso = reservedIso;
834
0
  }
835
836
  std::array<uint8_t, DOIP_RESERVED_OEM_LEN> DoIpRoutingActivationResponse::getReservedOem() const
837
0
  {
838
0
    if (!hasReservedOem())
839
0
      throw std::runtime_error("Reserved OEM field not present!");
840
841
0
    std::array<uint8_t, DOIP_RESERVED_OEM_LEN> reservedOem;
842
0
    memcpy(reservedOem.data(), m_Data + RESERVED_OEM_OFFSET, DOIP_RESERVED_OEM_LEN);
843
0
    return reservedOem;
844
0
  }
845
846
  void DoIpRoutingActivationResponse::setReservedOem(const std::array<uint8_t, DOIP_RESERVED_OEM_LEN>& reservedOem)
847
0
  {
848
0
    if (!hasReservedOem())
849
0
    {
850
0
      extendLayer(RESERVED_OEM_OFFSET, DOIP_RESERVED_OEM_LEN);
851
0
    }
852
0
    setPayloadLength(OPT_LEN - DOIP_HEADER_LEN);
853
0
    memcpy((m_Data + RESERVED_OEM_OFFSET), reservedOem.data(), DOIP_RESERVED_OEM_LEN);
854
0
  }
855
856
  bool DoIpRoutingActivationResponse::hasReservedOem() const
857
0
  {
858
0
    return (m_DataLen == OPT_LEN);
859
0
  }
860
861
  void DoIpRoutingActivationResponse::clearReservedOem()
862
0
  {
863
0
    if (!hasReservedOem())
864
0
    {
865
0
      PCPP_LOG_DEBUG("DoIP packet has no reserved OEM field!");
866
0
      return;
867
0
    }
868
869
0
    shortenLayer(FIXED_LEN, DOIP_RESERVED_OEM_LEN);
870
0
    setPayloadLength(FIXED_LEN - DOIP_HEADER_LEN);
871
0
    PCPP_LOG_DEBUG("Reserved OEM field has been removed successfully!");
872
0
  }
873
874
  std::string DoIpRoutingActivationResponse::getSummary() const
875
0
  {
876
0
    std::ostringstream oss;
877
0
    oss << "Logical Address (Tester): 0x" << std::hex << getLogicalAddressExternalTester() << "\n";
878
0
    oss << "Source Address: 0x" << std::hex << getSourceAddress() << "\n";
879
880
0
    auto it = DoIpEnumToStringRoutingResponseCodes.find(getResponseCode());
881
0
    oss << "Routing activation response code: " << it->second << " (0x" << std::hex
882
0
        << static_cast<unsigned>(getRoutingActivationResponse()->responseCode) << ")\n";
883
884
0
    oss << "Reserved by ISO: " << pcpp::byteArrayToHexString(getReservedIso().data(), DOIP_RESERVED_ISO_LEN)
885
0
        << "\n";
886
0
    if (hasReservedOem())
887
0
      oss << "Reserved by OEM: " << pcpp::byteArrayToHexString(getReservedOem().data(), DOIP_RESERVED_OEM_LEN)
888
0
          << "\n";
889
890
0
    return oss.str();
891
0
  }
892
893
  //~~~~~~~~~~~~~~~~~~~~~~|
894
  // DoIpAliveCheckRequest|
895
  //~~~~~~~~~~~~~~~~~~~~~~|
896
0
  DoIpAliveCheckRequest::DoIpAliveCheckRequest() : DoIpLayer(DOIP_HEADER_LEN)
897
0
  {
898
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, getPayloadType(), 0);
899
0
  }
900
901
  //~~~~~~~~~~~~~~~~~~~~~~~|
902
  // DoIpAliveCheckResponse|
903
  //~~~~~~~~~~~~~~~~~~~~~~~|
904
  DoIpAliveCheckResponse::DoIpAliveCheckResponse(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
905
0
      : DoIpLayer(data, dataLen, prevLayer, packet)
906
0
  {}
907
908
0
  DoIpAliveCheckResponse::DoIpAliveCheckResponse(uint16_t sourceAddress) : DoIpLayer(FIXED_LEN)
909
0
  {
910
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, getPayloadType(), DOIP_SOURCE_ADDRESS_LEN);
911
0
    setSourceAddress(sourceAddress);
912
0
  }
913
914
  uint16_t DoIpAliveCheckResponse::getSourceAddress() const
915
0
  {
916
0
    return be16toh(getAliveCheckResponse()->sourceAddress);
917
0
  }
918
919
  void DoIpAliveCheckResponse::setSourceAddress(uint16_t sourceAddress)
920
0
  {
921
0
    getAliveCheckResponse()->sourceAddress = htobe16(sourceAddress);
922
0
  }
923
924
  std::string DoIpAliveCheckResponse::getSummary() const
925
0
  {
926
0
    std::ostringstream oss;
927
0
    oss << "Source Address: " << std::hex << "0x" << getSourceAddress() << "\n";
928
0
    return oss.str();
929
0
  }
930
931
  //~~~~~~~~~~~~~~~~~~~~~~~~|
932
  // DoIpEntityStatusRequest|
933
  //~~~~~~~~~~~~~~~~~~~~~~~~|
934
0
  DoIpEntityStatusRequest::DoIpEntityStatusRequest() : DoIpLayer(DOIP_HEADER_LEN)
935
0
  {
936
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, getPayloadType(), 0);
937
0
  }
938
939
  //~~~~~~~~~~~~~~~~~~~~~~~~~|
940
  // DoIpEntityStatusResponse|
941
  //~~~~~~~~~~~~~~~~~~~~~~~~~|
942
  DoIpEntityStatusResponse::DoIpEntityStatusResponse(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
943
0
      : DoIpLayer(data, dataLen, prevLayer, packet)
944
0
  {}
945
946
  DoIpEntityStatusResponse::DoIpEntityStatusResponse(DoIpEntityStatusResponseCode nodeType,
947
                                                     uint8_t maxConcurrentSockets, uint8_t currentlyOpenSockets)
948
0
      : DoIpLayer(FIXED_LEN)
949
0
  {
950
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, getPayloadType(), (FIXED_LEN - DOIP_HEADER_LEN));
951
952
0
    setNodeType(nodeType);
953
0
    setMaxConcurrentSockets(maxConcurrentSockets);
954
0
    setCurrentlyOpenSockets(currentlyOpenSockets);
955
0
  }
956
  DoIpEntityStatusResponseCode DoIpEntityStatusResponse::getNodeType() const
957
0
  {
958
0
    uint8_t nodeType = getEntityStatusResponse()->nodeType;
959
0
    if (nodeType <= static_cast<uint8_t>(DoIpEntityStatusResponseCode::NODE))
960
0
    {
961
0
      return static_cast<DoIpEntityStatusResponseCode>(nodeType);
962
0
    }
963
0
    return DoIpEntityStatusResponseCode::UNKNOWN;
964
0
  }
965
966
  uint8_t DoIpEntityStatusResponse::getMaxConcurrentSockets() const
967
0
  {
968
0
    return getEntityStatusResponse()->maxConcurrentSockets;
969
0
  }
970
971
  uint8_t DoIpEntityStatusResponse::getCurrentlyOpenSockets() const
972
0
  {
973
0
    return getEntityStatusResponse()->currentlyOpenSockets;
974
0
  }
975
976
  uint32_t DoIpEntityStatusResponse::getMaxDataSize() const
977
0
  {
978
0
    if (!hasMaxDataSize())
979
0
      throw std::runtime_error("MaxDataSize field not present!");
980
981
0
    uint32_t value;
982
0
    std::memcpy(&value, m_Data + MAX_DATA_SIZE_OFFSET, MAX_DATA_SIZE_LEN);
983
0
    return be32toh(value);
984
0
  }
985
986
  void DoIpEntityStatusResponse::setNodeType(DoIpEntityStatusResponseCode nodeType)
987
0
  {
988
0
    getEntityStatusResponse()->nodeType = static_cast<uint8_t>(nodeType);
989
0
  }
990
991
  bool DoIpEntityStatusResponse::hasMaxDataSize() const
992
0
  {
993
0
    return (m_DataLen == OPT_LEN);
994
0
  }
995
996
  void DoIpEntityStatusResponse::clearMaxDataSize()
997
0
  {
998
0
    if (!hasMaxDataSize())
999
0
    {
1000
0
      PCPP_LOG_DEBUG("DoIP packet has no MaxDataSize field!");
1001
0
      return;
1002
0
    }
1003
0
    shortenLayer(MAX_DATA_SIZE_OFFSET, MAX_DATA_SIZE_LEN);
1004
0
    setPayloadLength(FIXED_LEN - DOIP_HEADER_LEN);
1005
0
    PCPP_LOG_DEBUG("MaxDataSize has been removed successfully!");
1006
0
  }
1007
1008
  void DoIpEntityStatusResponse::setMaxConcurrentSockets(uint8_t sockets)
1009
0
  {
1010
0
    getEntityStatusResponse()->maxConcurrentSockets = sockets;
1011
0
  }
1012
1013
  void DoIpEntityStatusResponse::setCurrentlyOpenSockets(uint8_t sockets)
1014
0
  {
1015
0
    getEntityStatusResponse()->currentlyOpenSockets = sockets;
1016
0
  }
1017
1018
  void DoIpEntityStatusResponse::setMaxDataSize(uint32_t data)
1019
0
  {
1020
0
    if (!hasMaxDataSize())
1021
0
    {
1022
0
      extendLayer(MAX_DATA_SIZE_OFFSET, MAX_DATA_SIZE_LEN);
1023
0
    }
1024
0
    uint32_t value = htobe32(data);
1025
0
    memcpy(m_Data + MAX_DATA_SIZE_OFFSET, &value, MAX_DATA_SIZE_LEN);
1026
0
    setPayloadLength(OPT_LEN - DOIP_HEADER_LEN);
1027
0
  }
1028
1029
  std::string DoIpEntityStatusResponse::getSummary() const
1030
0
  {
1031
0
    std::ostringstream oss;
1032
0
    auto it = DoIpEnumToStringEntityStatusNodeTypes.find(getNodeType());
1033
1034
0
    oss << "Entity status: " << it->second << " (0x" << std::hex
1035
0
        << static_cast<unsigned>(getEntityStatusResponse()->nodeType) << ")" << "\n";
1036
0
    oss << "Max Concurrent Socket: " << static_cast<unsigned>(getMaxConcurrentSockets()) << "\n";
1037
0
    oss << "Currently Opened Socket: " << static_cast<unsigned>(getCurrentlyOpenSockets()) << "\n";
1038
0
    if (hasMaxDataSize())
1039
0
    {
1040
0
      oss << "Max Data Size: "
1041
0
          << "0x" << pcpp::byteArrayToHexString((m_Data + MAX_DATA_SIZE_OFFSET), MAX_DATA_SIZE_LEN) << "\n";
1042
0
    }
1043
0
    return oss.str();
1044
0
  }
1045
1046
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
1047
  // DoIpDiagnosticPowerModeRequest|
1048
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
1049
0
  DoIpDiagnosticPowerModeRequest::DoIpDiagnosticPowerModeRequest() : DoIpLayer(DOIP_HEADER_LEN)
1050
0
  {
1051
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, getPayloadType(), 0);
1052
0
  }
1053
1054
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
1055
  // DoIpDiagnosticPowerModeResponse|
1056
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
1057
  DoIpDiagnosticPowerModeResponse::DoIpDiagnosticPowerModeResponse(uint8_t* data, size_t dataLen, Layer* prevLayer,
1058
                                                                   Packet* packet)
1059
0
      : DoIpLayer(data, dataLen, prevLayer, packet)
1060
0
  {}
1061
1062
  DoIpDiagnosticPowerModeResponse::DoIpDiagnosticPowerModeResponse(DoIpDiagnosticPowerModeCodes code)
1063
0
      : DoIpLayer(FIXED_LEN)
1064
0
  {
1065
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, getPayloadType(), (FIXED_LEN - DOIP_HEADER_LEN));
1066
0
    setPowerModeCode(code);
1067
0
  }
1068
1069
  DoIpDiagnosticPowerModeCodes DoIpDiagnosticPowerModeResponse::getPowerModeCode() const
1070
0
  {
1071
0
    uint8_t powerModeCode = getDiagnosticPowerModeResponse()->powerModeCode;
1072
0
    if (powerModeCode <= static_cast<uint8_t>(DoIpDiagnosticPowerModeCodes::NOT_SUPPORTED))
1073
0
    {
1074
0
      return static_cast<DoIpDiagnosticPowerModeCodes>(powerModeCode);
1075
0
    }
1076
0
    return DoIpDiagnosticPowerModeCodes::UNKNOWN;
1077
0
  }
1078
1079
  void DoIpDiagnosticPowerModeResponse::setPowerModeCode(DoIpDiagnosticPowerModeCodes code)
1080
0
  {
1081
0
    getDiagnosticPowerModeResponse()->powerModeCode = static_cast<uint8_t>(code);
1082
0
  }
1083
1084
  std::string DoIpDiagnosticPowerModeResponse::getSummary() const
1085
0
  {
1086
0
    std::ostringstream oss;
1087
0
    DoIpDiagnosticPowerModeCodes powerModeCode = getPowerModeCode();
1088
0
    auto it = DoIpEnumToStringDiagnosticPowerModeCodes.find(powerModeCode);
1089
0
    oss << "Diagnostic power mode: " << it->second << " (0x" << std::hex
1090
0
        << static_cast<unsigned>(getDiagnosticPowerModeResponse()->powerModeCode) << ")\n";
1091
0
    return oss.str();
1092
0
  }
1093
1094
  //~~~~~~~~~~~~~~~~~~~|
1095
  // DoIpDiagnosticBase|
1096
  //~~~~~~~~~~~~~~~~~~~|
1097
  DoIpDiagnosticBase::DoIpDiagnosticBase(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
1098
0
      : DoIpLayer(data, dataLen, prevLayer, packet)
1099
0
  {}
1100
1101
  uint16_t DoIpDiagnosticBase::getSourceAddress() const
1102
0
  {
1103
0
    return be16toh(getCommonDiagnosticHeader()->sourceAddress);
1104
0
  }
1105
1106
  void DoIpDiagnosticBase::setSourceAddress(uint16_t sourceAddress)
1107
0
  {
1108
0
    getCommonDiagnosticHeader()->sourceAddress = htobe16(sourceAddress);
1109
0
  }
1110
1111
  uint16_t DoIpDiagnosticBase::getTargetAddress() const
1112
0
  {
1113
0
    return be16toh(getCommonDiagnosticHeader()->targetAddress);
1114
0
  }
1115
1116
  void DoIpDiagnosticBase::setTargetAddress(uint16_t targetAddress)
1117
0
  {
1118
0
    getCommonDiagnosticHeader()->targetAddress = htobe16(targetAddress);
1119
0
  }
1120
1121
  //~~~~~~~~~~~~~~~~~~~~~~|
1122
  // DoIpDiagnosticMessage|
1123
  //~~~~~~~~~~~~~~~~~~~~~~|
1124
  DoIpDiagnosticMessage::DoIpDiagnosticMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
1125
0
      : DoIpDiagnosticBase(data, dataLen, prevLayer, packet)
1126
0
  {}
1127
1128
  DoIpDiagnosticMessage::DoIpDiagnosticMessage(uint16_t sourceAddress, uint16_t targetAddress,
1129
                                               const std::vector<uint8_t>& diagnosticData)
1130
0
      : DoIpDiagnosticBase(MIN_LEN + diagnosticData.size())
1131
0
  {
1132
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, getPayloadType(), MIN_LEN + diagnosticData.size());
1133
0
    setSourceAddress(sourceAddress);
1134
0
    setTargetAddress(targetAddress);
1135
0
    setDiagnosticData(diagnosticData);
1136
0
  }
1137
1138
  std::vector<uint8_t> DoIpDiagnosticMessage::getDiagnosticData() const
1139
0
  {
1140
0
    const uint8_t* diagDataPtr = m_Data + DIAGNOSTIC_DATA_OFFSET;
1141
0
    return std::vector<uint8_t>(diagDataPtr, diagDataPtr + (m_DataLen - DIAGNOSTIC_DATA_OFFSET));
1142
0
  }
1143
1144
  void DoIpDiagnosticMessage::setDiagnosticData(const std::vector<uint8_t>& data)
1145
0
  {
1146
0
    const size_t newPayloadLength = DOIP_SOURCE_ADDRESS_LEN + DOIP_TARGET_ADDRESS_LEN + data.size();
1147
0
    const size_t currentDiagnosticDataLen = m_DataLen - DIAGNOSTIC_DATA_OFFSET;
1148
0
    setPayloadLength(newPayloadLength);
1149
1150
0
    ptrdiff_t layerExtensionLen =
1151
0
        static_cast<ptrdiff_t>(data.size()) - static_cast<ptrdiff_t>(currentDiagnosticDataLen);
1152
0
    if (layerExtensionLen > 0)
1153
0
    {
1154
0
      extendLayer(DIAGNOSTIC_DATA_OFFSET + currentDiagnosticDataLen, layerExtensionLen);
1155
0
    }
1156
0
    else if (layerExtensionLen < 0)
1157
0
    {
1158
0
      shortenLayer(DIAGNOSTIC_DATA_OFFSET + data.size(), (-1 * layerExtensionLen));
1159
0
    }
1160
0
    memcpy((m_Data + DIAGNOSTIC_DATA_OFFSET), data.data(), data.size());
1161
0
  }
1162
1163
  std::string DoIpDiagnosticMessage::getSummary() const
1164
0
  {
1165
0
    std::ostringstream oss;
1166
0
    oss << "Source Address: " << std::hex << "0x" << getSourceAddress() << "\n";
1167
0
    oss << "Target Address: " << std::hex << "0x" << getTargetAddress() << "\n";
1168
    // Diagnostic data should be parsed by nextLayer (uds layer)
1169
0
    return oss.str();
1170
0
  }
1171
1172
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
1173
  // DoIpDiagnosticResponseMessageBase|
1174
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
1175
  DoIpDiagnosticResponseMessageBase::DoIpDiagnosticResponseMessageBase(uint8_t* data, size_t dataLen,
1176
                                                                       Layer* prevLayer, Packet* packet)
1177
0
      : DoIpDiagnosticBase(data, dataLen, prevLayer, packet)
1178
0
  {}
1179
1180
  DoIpDiagnosticResponseMessageBase::DoIpDiagnosticResponseMessageBase(uint16_t sourceAddress, uint16_t targetAddress,
1181
                                                                       DoIpPayloadTypes type)
1182
0
      : DoIpDiagnosticBase(FIXED_LEN)
1183
0
  {
1184
0
    setHeaderFields(DoIpProtocolVersion::ISO13400_2012, type, (FIXED_LEN - DOIP_HEADER_LEN));
1185
0
    setSourceAddress(sourceAddress);
1186
0
    setTargetAddress(targetAddress);
1187
0
  }
1188
1189
  void DoIpDiagnosticResponseMessageBase::setResponseCode(uint8_t code)
1190
0
  {
1191
0
    getDiagnosticResponseMessageBase()->diagnosticCode = code;
1192
0
  }
1193
1194
  uint8_t DoIpDiagnosticResponseMessageBase::getResponseCode() const
1195
0
  {
1196
0
    return getDiagnosticResponseMessageBase()->diagnosticCode;
1197
0
  }
1198
1199
  std::vector<uint8_t> DoIpDiagnosticResponseMessageBase::getPreviousMessage() const
1200
0
  {
1201
0
    if (!hasPreviousMessage())
1202
0
      return {};
1203
1204
0
    const uint8_t* dataPtr = m_Data + PREVIOUS_MSG_OFFSET;
1205
0
    return std::vector<uint8_t>(dataPtr, dataPtr + (m_DataLen - PREVIOUS_MSG_OFFSET));
1206
0
  }
1207
1208
  bool DoIpDiagnosticResponseMessageBase::hasPreviousMessage() const
1209
0
  {
1210
0
    return (m_DataLen > FIXED_LEN);
1211
0
  }
1212
1213
  void DoIpDiagnosticResponseMessageBase::setPreviousMessage(const std::vector<uint8_t>& msg)
1214
0
  {
1215
0
    const size_t newPayloadLen = FIXED_LEN - DOIP_HEADER_LEN + msg.size();
1216
0
    const size_t currentPayloadLen = m_DataLen - PREVIOUS_MSG_OFFSET;
1217
0
    setPayloadLength(newPayloadLen);
1218
1219
0
    int layerExtensionLen = static_cast<int>(msg.size()) - static_cast<int>(currentPayloadLen);
1220
0
    if (layerExtensionLen > 0)
1221
0
    {
1222
0
      extendLayer(PREVIOUS_MSG_OFFSET + currentPayloadLen, layerExtensionLen);
1223
0
    }
1224
0
    else if (layerExtensionLen < 0)
1225
0
    {
1226
0
      shortenLayer(PREVIOUS_MSG_OFFSET + msg.size(), (-1 * layerExtensionLen));
1227
0
    }
1228
0
    memcpy((m_Data + PREVIOUS_MSG_OFFSET), msg.data(), msg.size());
1229
0
  }
1230
1231
  void DoIpDiagnosticResponseMessageBase::clearPreviousMessage()
1232
0
  {
1233
0
    if (!hasPreviousMessage())
1234
0
    {
1235
0
      PCPP_LOG_DEBUG("DoIP packet has no PreviousMessage field!");
1236
0
      return;
1237
0
    }
1238
0
    shortenLayer(FIXED_LEN, (m_DataLen - FIXED_LEN));
1239
0
    setPayloadLength(FIXED_LEN - DOIP_HEADER_LEN);
1240
0
    PCPP_LOG_DEBUG("PreviousMessage field has been removed successfully!");
1241
0
  }
1242
1243
  //~~~~~~~~~~~~~~~~~~~~~~~~~|
1244
  // DoIpDiagnosticMessageAck|
1245
  //~~~~~~~~~~~~~~~~~~~~~~~~~|
1246
  DoIpDiagnosticMessageAck::DoIpDiagnosticMessageAck(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
1247
0
      : DoIpDiagnosticResponseMessageBase(data, dataLen, prevLayer, packet)
1248
0
  {}
1249
1250
  DoIpDiagnosticMessageAck::DoIpDiagnosticMessageAck(uint16_t sourceAddress, uint16_t targetAddress,
1251
                                                     DoIpDiagnosticAckCodes ackCode)
1252
0
      : DoIpDiagnosticResponseMessageBase(sourceAddress, targetAddress, getPayloadType())
1253
0
  {
1254
0
    setAckCode(ackCode);
1255
0
  }
1256
1257
  DoIpDiagnosticAckCodes DoIpDiagnosticMessageAck::getAckCode() const
1258
0
  {
1259
0
    return (getResponseCode() == static_cast<uint8_t>(DoIpDiagnosticAckCodes::ACK))
1260
0
               ? DoIpDiagnosticAckCodes::ACK
1261
0
               : DoIpDiagnosticAckCodes::UNKNOWN;
1262
0
  }
1263
1264
  void DoIpDiagnosticMessageAck::setAckCode(DoIpDiagnosticAckCodes code)
1265
0
  {
1266
0
    setResponseCode(static_cast<uint8_t>(code));
1267
0
  }
1268
1269
  std::string DoIpDiagnosticMessageAck::getSummary() const
1270
0
  {
1271
0
    std::ostringstream oss;
1272
0
    DoIpDiagnosticAckCodes ackCode = getAckCode();
1273
0
    oss << "Source Address: " << std::hex << "0x" << getSourceAddress() << "\n";
1274
0
    oss << "Target Address: " << std::hex << "0x" << getTargetAddress() << "\n";
1275
0
    auto it = DoIpEnumToStringAckCode.find(ackCode);
1276
0
    oss << "ACK code: " << it->second << " (0x" << static_cast<unsigned>(getResponseCode()) << ")\n";
1277
0
    if (hasPreviousMessage())
1278
0
    {
1279
0
      oss << "Previous message: "
1280
0
          << pcpp::byteArrayToHexString(getPreviousMessage().data(), getPreviousMessage().size()) << "\n";
1281
0
    }
1282
0
    return oss.str();
1283
0
  }
1284
1285
  //~~~~~~~~~~~~~~~~~~~~~~~~~~|
1286
  // DoIpDiagnosticMessageNack|
1287
  //~~~~~~~~~~~~~~~~~~~~~~~~~~|
1288
  DoIpDiagnosticMessageNack::DoIpDiagnosticMessageNack(uint8_t* data, size_t dataLen, Layer* prevLayer,
1289
                                                       Packet* packet)
1290
0
      : DoIpDiagnosticResponseMessageBase(data, dataLen, prevLayer, packet)
1291
0
  {}
1292
1293
  DoIpDiagnosticMessageNack::DoIpDiagnosticMessageNack(uint16_t sourceAddress, uint16_t targetAddress,
1294
                                                       DoIpDiagnosticMessageNackCodes nackCode)
1295
0
      : DoIpDiagnosticResponseMessageBase(sourceAddress, targetAddress, getPayloadType())
1296
0
  {
1297
0
    setNackCode(nackCode);
1298
0
  }
1299
1300
  DoIpDiagnosticMessageNackCodes DoIpDiagnosticMessageNack::getNackCode() const
1301
0
  {
1302
0
    uint8_t nackCode = getResponseCode();
1303
0
    if (nackCode <= static_cast<uint8_t>(DoIpDiagnosticMessageNackCodes::TRANSPORT_PROTOCOL_ERROR))
1304
0
    {
1305
0
      return static_cast<DoIpDiagnosticMessageNackCodes>(nackCode);
1306
0
    }
1307
0
    return DoIpDiagnosticMessageNackCodes::UNKNOWN;
1308
0
  }
1309
1310
  void DoIpDiagnosticMessageNack::setNackCode(DoIpDiagnosticMessageNackCodes code)
1311
0
  {
1312
0
    setResponseCode(static_cast<uint8_t>(code));
1313
0
  }
1314
1315
  std::string DoIpDiagnosticMessageNack::getSummary() const
1316
0
  {
1317
0
    std::ostringstream oss;
1318
0
    DoIpDiagnosticMessageNackCodes nackCode = getNackCode();
1319
0
    oss << "Source Address: 0x" << std::hex << getSourceAddress() << "\n";
1320
0
    oss << "Target Address: 0x" << std::hex << getTargetAddress() << "\n";
1321
1322
0
    auto it = DoIpEnumToStringDiagnosticNackCodes.find(nackCode);
1323
0
    oss << "NACK code: " << it->second << " (0x" << static_cast<unsigned>(getResponseCode()) << ")\n";
1324
1325
0
    if (hasPreviousMessage())
1326
0
    {
1327
0
      oss << "Previous message: "
1328
0
          << pcpp::byteArrayToHexString(getPreviousMessage().data(), getPreviousMessage().size()) << "\n";
1329
0
    }
1330
0
    return oss.str();
1331
0
  }
1332
}  // namespace pcpp