Coverage Report

Created: 2026-01-09 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/IcmpV6Layer.cpp
Line
Count
Source
1
#define LOG_MODULE PacketLogModuleIcmpV6Layer
2
3
#include "IcmpV6Layer.h"
4
#include "EndianPortable.h"
5
#include "IPv4Layer.h"
6
#include "IPv6Layer.h"
7
#include "NdpLayer.h"
8
#include "PacketUtils.h"
9
#include "PayloadLayer.h"
10
#include <sstream>
11
12
// IcmpV6Layer
13
14
namespace pcpp
15
{
16
17
  Layer* IcmpV6Layer::parseIcmpV6Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
18
0
  {
19
0
    if (dataLen < sizeof(icmpv6hdr))
20
0
      return new PayloadLayer(data, dataLen, prevLayer, packet);
21
22
0
    icmpv6hdr* hdr = (icmpv6hdr*)data;
23
0
    ICMPv6MessageType messageType = static_cast<ICMPv6MessageType>(hdr->type);
24
25
0
    switch (messageType)
26
0
    {
27
0
    case ICMPv6MessageType::ICMPv6_ECHO_REQUEST:
28
0
    case ICMPv6MessageType::ICMPv6_ECHO_REPLY:
29
0
      return new ICMPv6EchoLayer(data, dataLen, prevLayer, packet);
30
0
    case ICMPv6MessageType::ICMPv6_NEIGHBOR_SOLICITATION:
31
0
      return new NDPNeighborSolicitationLayer(data, dataLen, prevLayer, packet);
32
0
    case ICMPv6MessageType::ICMPv6_NEIGHBOR_ADVERTISEMENT:
33
0
      return new NDPNeighborAdvertisementLayer(data, dataLen, prevLayer, packet);
34
0
    case ICMPv6MessageType::ICMPv6_UNKNOWN_MESSAGE:
35
0
      return new PayloadLayer(data, dataLen, prevLayer, packet);
36
0
    default:
37
0
      return new IcmpV6Layer(data, dataLen, prevLayer, packet);
38
0
    }
39
0
  }
40
41
  IcmpV6Layer::IcmpV6Layer(ICMPv6MessageType msgType, uint8_t code, const uint8_t* data, size_t dataLen)
42
0
  {
43
0
    m_DataLen = sizeof(icmpv6hdr) + dataLen;
44
0
    m_Data = new uint8_t[m_DataLen];
45
0
    memset(m_Data, 0, m_DataLen);
46
0
    m_Protocol = ICMPv6;
47
48
0
    icmpv6hdr* hdr = (icmpv6hdr*)m_Data;
49
0
    hdr->type = static_cast<uint8_t>(msgType);
50
0
    hdr->code = code;
51
52
0
    if (data != nullptr && dataLen > 0)
53
0
      memcpy(m_Data + sizeof(icmpv6hdr), data, dataLen);
54
0
  }
55
56
  ICMPv6MessageType IcmpV6Layer::getMessageType() const
57
0
  {
58
0
    return static_cast<ICMPv6MessageType>(getIcmpv6Header()->type);
59
0
  }
60
61
  uint8_t IcmpV6Layer::getCode() const
62
0
  {
63
0
    return getIcmpv6Header()->code;
64
0
  }
65
66
  uint16_t IcmpV6Layer::getChecksum() const
67
0
  {
68
0
    return be16toh(getIcmpv6Header()->checksum);
69
0
  }
70
71
  void IcmpV6Layer::computeCalculateFields()
72
0
  {
73
0
    calculateChecksum();
74
0
  }
75
76
  void IcmpV6Layer::calculateChecksum()
77
0
  {
78
    // Pseudo header of 40 bytes which is composed as follows(in order):
79
    // - 16 bytes for the source address
80
    // - 16 bytes for the destination address
81
    // - 4 bytes big endian payload length(the same value as in the IPv6 header)
82
    // - 3 bytes zero + 1 byte nextheader( 58 decimal) big endian
83
84
0
    getIcmpv6Header()->checksum = 0;
85
86
0
    if (m_PrevLayer != nullptr)
87
0
    {
88
0
      ScalarBuffer<uint16_t> vec[2];
89
90
0
      vec[0].buffer = (uint16_t*)m_Data;
91
0
      vec[0].len = m_DataLen;
92
93
0
      const unsigned int pseudoHeaderLen = 40;
94
0
      const unsigned int bigEndianLen = htobe32(m_DataLen);
95
0
      const unsigned int bigEndianNextHeader = htobe32(PACKETPP_IPPROTO_ICMPV6);
96
97
0
      uint16_t pseudoHeader[pseudoHeaderLen / 2];
98
0
      ((IPv6Layer*)m_PrevLayer)->getSrcIPv6Address().copyTo((uint8_t*)pseudoHeader);
99
0
      ((IPv6Layer*)m_PrevLayer)->getDstIPv6Address().copyTo((uint8_t*)(pseudoHeader + 8));
100
0
      memcpy(&pseudoHeader[16], &bigEndianLen, sizeof(uint32_t));
101
0
      memcpy(&pseudoHeader[18], &bigEndianNextHeader, sizeof(uint32_t));
102
0
      vec[1].buffer = pseudoHeader;
103
0
      vec[1].len = pseudoHeaderLen;
104
105
      // Calculate and write checksum
106
0
      getIcmpv6Header()->checksum = htobe16(computeChecksum(vec, 2));
107
0
    }
108
0
  }
109
110
  std::string IcmpV6Layer::toString() const
111
0
  {
112
0
    std::ostringstream typeStream;
113
0
    typeStream << (int)getMessageType();
114
0
    return "ICMPv6 Layer, Message type: " + typeStream.str();
115
0
  }
116
117
  //
118
  // ICMPv6EchoLayer
119
  //
120
121
  ICMPv6EchoLayer::ICMPv6EchoLayer(ICMPv6EchoType echoType, uint16_t id, uint16_t sequence, const uint8_t* data,
122
                                   size_t dataLen)
123
0
  {
124
0
    m_DataLen = sizeof(icmpv6_echo_hdr) + dataLen;
125
0
    m_Data = new uint8_t[m_DataLen];
126
0
    memset(m_Data, 0, m_DataLen);
127
0
    m_Protocol = ICMPv6;
128
129
0
    icmpv6_echo_hdr* header = getEchoHeader();
130
131
0
    switch (echoType)
132
0
    {
133
0
    case REPLY:
134
0
      header->type = static_cast<uint8_t>(ICMPv6MessageType::ICMPv6_ECHO_REPLY);
135
0
      break;
136
0
    case REQUEST:
137
0
    default:
138
0
      header->type = static_cast<uint8_t>(ICMPv6MessageType::ICMPv6_ECHO_REQUEST);
139
0
      break;
140
0
    }
141
142
0
    header->code = 0;
143
0
    header->checksum = 0;
144
0
    header->id = htobe16(id);
145
0
    header->sequence = htobe16(sequence);
146
147
0
    if (data != nullptr && dataLen > 0)
148
0
      memcpy(getEchoDataPtr(), data, dataLen);
149
0
  }
150
151
  uint16_t ICMPv6EchoLayer::getIdentifier() const
152
0
  {
153
0
    return be16toh(getEchoHeader()->id);
154
0
  }
155
156
  uint16_t ICMPv6EchoLayer::getSequenceNr() const
157
0
  {
158
0
    return be16toh(getEchoHeader()->sequence);
159
0
  }
160
161
  std::string ICMPv6EchoLayer::toString() const
162
0
  {
163
0
    std::ostringstream typeStream;
164
0
    typeStream << (int)getMessageType();
165
0
    return "ICMPv6 Layer, Echo Request/Reply Message (type: " + typeStream.str() + ")";
166
0
  }
167
168
}  // namespace pcpp