/src/PcapPlusPlus/Packet++/src/VrrpLayer.cpp
Line | Count | Source |
1 | 0 | #define LOG_MODULE PacketLogModuleVrrpLayer |
2 | | |
3 | | #include <SystemUtils.h> |
4 | | #include "PacketUtils.h" |
5 | | #include "Logger.h" |
6 | | #include "EndianPortable.h" |
7 | | #include "IPv4Layer.h" |
8 | | #include "PayloadLayer.h" |
9 | | #include "VrrpLayer.h" |
10 | | |
11 | | namespace pcpp |
12 | | { |
13 | | |
14 | | constexpr uint8_t VrrpPriorityStop = 0; ///< priority to stop |
15 | | constexpr uint8_t VrrpPriorityDefault = 100; ///< default priority |
16 | | constexpr uint8_t VrrpPriorityOwner = 255; ///< priority of the IP owner |
17 | | |
18 | | constexpr uint8_t VrrpPacketFixedLength = 8; |
19 | | constexpr uint8_t VrrpPacketMaxIpAddressCount = 255; |
20 | | |
21 | | constexpr uint8_t VrrpVersion2 = 2; |
22 | | constexpr uint8_t VrrpVersion3 = 3; |
23 | | |
24 | | // -------- Class VrrpLayer ----------------- |
25 | | |
26 | | VrrpLayer::VrrpLayer(ProtocolType subProtocol, uint8_t virtualRouterId, uint8_t priority) |
27 | 0 | { |
28 | 0 | allocData(VrrpPacketFixedLength); |
29 | 0 | m_Protocol = subProtocol; |
30 | 0 | m_AddressType = IPAddress::IPv4AddressType; |
31 | 0 | auto vrrpHeader = getVrrpHeader(); |
32 | 0 | if (subProtocol == VRRPv2) |
33 | 0 | { |
34 | 0 | vrrpHeader->version = VrrpVersion2; |
35 | 0 | } |
36 | 0 | else if (subProtocol == VRRPv3) |
37 | 0 | { |
38 | 0 | vrrpHeader->version = VrrpVersion3; |
39 | 0 | } |
40 | 0 | vrrpHeader->type = static_cast<uint8_t>(VrrpType::VrrpType_Advertisement); |
41 | 0 | setVirtualRouterID(virtualRouterId); |
42 | 0 | setPriority(priority); |
43 | 0 | } |
44 | | |
45 | | ProtocolType VrrpLayer::getVersionFromData(uint8_t* data, size_t dataLen) |
46 | 10.8k | { |
47 | 10.8k | if (!data || dataLen <= VrrpPacketFixedLength) |
48 | 9 | { |
49 | 9 | return UnknownProtocol; |
50 | 9 | } |
51 | | |
52 | 10.8k | auto* vrrpPacketCommon = (vrrp_header*)data; |
53 | 10.8k | uint8_t version = vrrpPacketCommon->version; |
54 | 10.8k | switch (version) |
55 | 10.8k | { |
56 | 3.30k | case VrrpVersion2: |
57 | 3.30k | return VRRPv2; |
58 | 7.07k | case VrrpVersion3: |
59 | 7.07k | return VRRPv3; |
60 | 459 | default: |
61 | 459 | return UnknownProtocol; |
62 | 10.8k | } |
63 | 10.8k | } |
64 | | |
65 | | void VrrpLayer::computeCalculateFields() |
66 | 2.24k | { |
67 | | // calculate and fill the checksum to packet |
68 | 2.24k | calculateAndSetChecksum(); |
69 | 2.24k | } |
70 | | |
71 | | uint8_t VrrpLayer::getIPAddressLen() const |
72 | 29.5k | { |
73 | 29.5k | if (getAddressType() == IPAddress::IPv4AddressType) |
74 | 28.6k | { |
75 | 28.6k | return 4; |
76 | 28.6k | } |
77 | | |
78 | 846 | return 16; |
79 | 29.5k | } |
80 | | |
81 | | bool VrrpLayer::isChecksumCorrect() const |
82 | 2.24k | { |
83 | 2.24k | auto vrrpHeader = getVrrpHeader(); |
84 | 2.24k | if (vrrpHeader == nullptr) |
85 | 0 | { |
86 | 0 | return false; |
87 | 0 | } |
88 | | |
89 | 2.24k | return (calculateChecksum() == be16toh(vrrpHeader->checksum)); |
90 | 2.24k | } |
91 | | |
92 | | VrrpLayer::VrrpPriority VrrpLayer::getPriorityAsEnum() const |
93 | 2.24k | { |
94 | 2.24k | switch (getVrrpHeader()->priority) |
95 | 2.24k | { |
96 | 169 | case VrrpPriorityDefault: |
97 | 169 | return VrrpLayer::VrrpPriority::Default; |
98 | | |
99 | 678 | case VrrpPriorityStop: |
100 | 678 | return VrrpLayer::VrrpPriority::Stop; |
101 | | |
102 | 66 | case VrrpPriorityOwner: |
103 | 66 | return VrrpLayer::VrrpPriority::Owner; |
104 | | |
105 | 1.33k | default: |
106 | 1.33k | return VrrpLayer::VrrpPriority::Other; |
107 | 2.24k | } |
108 | 2.24k | } |
109 | | |
110 | | std::string VrrpLayer::toString() const |
111 | 4.48k | { |
112 | 4.48k | return "VRRP v" + std::to_string(getVersion()) + |
113 | 4.48k | " Layer, virtual router ID: " + std::to_string(getVirtualRouterID()) + |
114 | 4.48k | ", IP address count: " + std::to_string(getIPAddressesCount()); |
115 | 4.48k | } |
116 | | |
117 | | uint8_t VrrpLayer::getVersion() const |
118 | 4.48k | { |
119 | 4.48k | return getVrrpHeader()->version; |
120 | 4.48k | } |
121 | | |
122 | | VrrpLayer::VrrpType VrrpLayer::getType() const |
123 | 2.24k | { |
124 | 2.24k | if (getVrrpHeader()->type == VrrpType_Advertisement) |
125 | 701 | { |
126 | 701 | return VrrpType_Advertisement; |
127 | 701 | } |
128 | | |
129 | 1.54k | return VrrpType_Unknown; |
130 | 2.24k | } |
131 | | |
132 | | uint8_t VrrpLayer::getVirtualRouterID() const |
133 | 4.48k | { |
134 | 4.48k | return getVrrpHeader()->vrId; |
135 | 4.48k | } |
136 | | |
137 | | void VrrpLayer::setVirtualRouterID(uint8_t virtualRouterID) |
138 | 0 | { |
139 | 0 | getVrrpHeader()->vrId = virtualRouterID; |
140 | 0 | } |
141 | | |
142 | | uint8_t VrrpLayer::getPriority() const |
143 | 2.24k | { |
144 | 2.24k | return getVrrpHeader()->priority; |
145 | 2.24k | } |
146 | | |
147 | | void VrrpLayer::setPriority(uint8_t priority) |
148 | 0 | { |
149 | 0 | getVrrpHeader()->priority = priority; |
150 | 0 | } |
151 | | |
152 | | uint16_t VrrpLayer::getChecksum() const |
153 | 2.24k | { |
154 | 2.24k | return be16toh(getVrrpHeader()->checksum); |
155 | 2.24k | } |
156 | | |
157 | | void VrrpLayer::calculateAndSetChecksum() |
158 | 2.24k | { |
159 | 2.24k | getVrrpHeader()->checksum = htobe16(calculateChecksum()); |
160 | 2.24k | } |
161 | | |
162 | | uint8_t VrrpLayer::getIPAddressesCount() const |
163 | 4.48k | { |
164 | 4.48k | return getVrrpHeader()->ipAddrCount; |
165 | 4.48k | } |
166 | | |
167 | | std::vector<IPAddress> VrrpLayer::getIPAddresses() const |
168 | 2.24k | { |
169 | 2.24k | std::vector<IPAddress> ipAddressesVec; |
170 | 2.24k | auto ipAddressesPtr = getFirstIPAddressPtr(); |
171 | 29.5k | while (ipAddressesPtr != nullptr) |
172 | 27.2k | { |
173 | 27.2k | IPAddress ipAddress = getIPAddressFromData(ipAddressesPtr); |
174 | 27.2k | ipAddressesVec.push_back(ipAddress); |
175 | 27.2k | ipAddressesPtr = getNextIPAddressPtr(ipAddressesPtr); |
176 | 27.2k | } |
177 | | |
178 | 2.24k | return ipAddressesVec; |
179 | 2.24k | } |
180 | | |
181 | | uint8_t* VrrpLayer::getFirstIPAddressPtr() const |
182 | 2.24k | { |
183 | 2.24k | size_t ipAddressLen = getIPAddressLen(); |
184 | | |
185 | | // check if there are virtual IP address at all |
186 | 2.24k | if (getHeaderLen() <= VrrpPacketFixedLength + ipAddressLen) |
187 | 806 | { |
188 | 806 | return nullptr; |
189 | 806 | } |
190 | | |
191 | 1.43k | return (m_Data + VrrpPacketFixedLength); |
192 | 2.24k | } |
193 | | |
194 | | uint8_t* VrrpLayer::getNextIPAddressPtr(uint8_t* ipAddressPtr) const |
195 | 27.2k | { |
196 | 27.2k | if (ipAddressPtr == nullptr) |
197 | 0 | { |
198 | 0 | return nullptr; |
199 | 0 | } |
200 | | |
201 | 27.2k | size_t ipAddressLen = getIPAddressLen(); |
202 | 27.2k | size_t nextOffset = static_cast<size_t>(ipAddressPtr - m_Data) + ipAddressLen; |
203 | | |
204 | | // The next virtual IP address must fit entirely inside the layer. Checking only that the current |
205 | | // address ends inside it leaves a trailing partial address reachable, which the caller then reads |
206 | | // in full and runs past the end of the buffer. |
207 | 27.2k | if (nextOffset + ipAddressLen > getHeaderLen()) |
208 | 1.43k | { |
209 | 1.43k | return nullptr; |
210 | 1.43k | } |
211 | | |
212 | 25.8k | return (m_Data + nextOffset); |
213 | 27.2k | } |
214 | | |
215 | | bool VrrpLayer::addIPAddressesAt(const std::vector<IPAddress>& ipAddresses, int offset) |
216 | 0 | { |
217 | 0 | if (offset > (int)getHeaderLen()) |
218 | 0 | { |
219 | 0 | PCPP_LOG_ERROR("Cannot add virtual IP address offset(" << offset << ") is out of layer bounds"); |
220 | 0 | return false; |
221 | 0 | } |
222 | | |
223 | 0 | for (auto ipAddress : ipAddresses) |
224 | 0 | { |
225 | 0 | if (!isIPAddressValid(ipAddress)) |
226 | 0 | { |
227 | 0 | PCPP_LOG_ERROR("Cannot add virtual IP address, for IP address is invalid."); |
228 | 0 | return false; |
229 | 0 | } |
230 | 0 | } |
231 | | |
232 | 0 | if (getIPAddressesCount() + ipAddresses.size() > VrrpPacketMaxIpAddressCount) |
233 | 0 | { |
234 | 0 | PCPP_LOG_ERROR("Cannot add virtual IP address, for virtual IP address has already exceed maximum."); |
235 | 0 | return false; |
236 | 0 | } |
237 | | |
238 | 0 | size_t ipAddrLen = getIPAddressLen(); |
239 | 0 | size_t ipAddressesLen = ipAddrLen * ipAddresses.size(); |
240 | 0 | if (ipAddressesLen == 0) |
241 | 0 | { |
242 | 0 | return true; |
243 | 0 | } |
244 | | |
245 | 0 | if (!extendLayer(offset, ipAddressesLen)) |
246 | 0 | { |
247 | 0 | PCPP_LOG_ERROR("Cannot add virtual IP address, cannot extend layer"); |
248 | 0 | return false; |
249 | 0 | } |
250 | | |
251 | 0 | size_t ipAddrOffset = 0; |
252 | 0 | uint8_t* newIpAddresses = getData() + offset; |
253 | 0 | for (auto const& ipAddress : ipAddresses) |
254 | 0 | { |
255 | 0 | copyIPAddressToData(newIpAddresses + ipAddrOffset, ipAddress); |
256 | 0 | ipAddrOffset += ipAddrLen; |
257 | 0 | } |
258 | |
|
259 | 0 | getVrrpHeader()->ipAddrCount = getIPAddressesCount() + ipAddresses.size(); |
260 | |
|
261 | 0 | return true; |
262 | 0 | } |
263 | | |
264 | | bool VrrpLayer::addIPAddresses(const std::vector<IPAddress>& ipAddresses) |
265 | 0 | { |
266 | 0 | return addIPAddressesAt(ipAddresses, (int)getHeaderLen()); |
267 | 0 | } |
268 | | |
269 | | bool VrrpLayer::addIPAddress(const IPAddress& ipAddress) |
270 | 0 | { |
271 | 0 | std::vector<IPAddress> ipAddresses; |
272 | 0 | ipAddresses.push_back(ipAddress); |
273 | |
|
274 | 0 | return addIPAddressesAt(ipAddresses, (int)getHeaderLen()); |
275 | 0 | } |
276 | | |
277 | | bool VrrpLayer::removeIPAddressAtIndex(int index) |
278 | 0 | { |
279 | 0 | int ipAddressCount = (int)getIPAddressesCount(); |
280 | |
|
281 | 0 | if (index < 0 || index >= ipAddressCount) |
282 | 0 | { |
283 | 0 | PCPP_LOG_ERROR("Cannot remove virtual IP address, index " << index << " is out of bounds"); |
284 | 0 | return false; |
285 | 0 | } |
286 | | |
287 | 0 | size_t ipAddressLen = getIPAddressLen(); |
288 | |
|
289 | 0 | size_t offset = VrrpPacketFixedLength; |
290 | 0 | auto curIpAddressPtr = getFirstIPAddressPtr(); |
291 | 0 | for (int i = 0; i < index; i++) |
292 | 0 | { |
293 | 0 | if (curIpAddressPtr == nullptr) |
294 | 0 | { |
295 | 0 | PCPP_LOG_ERROR("Cannot remove virtual IP address at index " |
296 | 0 | << index << ", cannot find virtual IP address at index " << i); |
297 | 0 | return false; |
298 | 0 | } |
299 | | |
300 | 0 | offset += ipAddressLen; |
301 | 0 | curIpAddressPtr = getNextIPAddressPtr(curIpAddressPtr); |
302 | 0 | } |
303 | | |
304 | 0 | if (!shortenLayer((int)offset, ipAddressLen)) |
305 | 0 | { |
306 | 0 | PCPP_LOG_ERROR("Cannot remove virtual IP address at index " << index << ", cannot shorted layer"); |
307 | 0 | return false; |
308 | 0 | } |
309 | | |
310 | 0 | getVrrpHeader()->ipAddrCount = ipAddressCount - 1; |
311 | |
|
312 | 0 | return true; |
313 | 0 | } |
314 | | |
315 | | bool VrrpLayer::removeAllIPAddresses() |
316 | 0 | { |
317 | 0 | size_t offset = VrrpPacketFixedLength; |
318 | 0 | size_t packetLen = getHeaderLen(); |
319 | 0 | if (packetLen <= offset) |
320 | 0 | { |
321 | 0 | return false; |
322 | 0 | } |
323 | | |
324 | 0 | if (!shortenLayer((int)offset, packetLen - offset)) |
325 | 0 | { |
326 | 0 | PCPP_LOG_ERROR("Cannot remove all virtual IP address(es), cannot shorted layer"); |
327 | 0 | return false; |
328 | 0 | } |
329 | | |
330 | 0 | getVrrpHeader()->ipAddrCount = 0; |
331 | |
|
332 | 0 | return true; |
333 | 0 | } |
334 | | |
335 | | void VrrpLayer::copyIPAddressToData(uint8_t* data, const IPAddress& ipAddress) const |
336 | 0 | { |
337 | 0 | size_t ipAddressLen = getIPAddressLen(); |
338 | |
|
339 | 0 | if (ipAddress.isIPv4()) |
340 | 0 | { |
341 | 0 | memcpy(data, ipAddress.getIPv4().toBytes(), ipAddressLen); |
342 | 0 | } |
343 | 0 | else if (ipAddress.isIPv6()) |
344 | 0 | { |
345 | 0 | memcpy(data, ipAddress.getIPv6().toBytes(), ipAddressLen); |
346 | 0 | } |
347 | 0 | } |
348 | | |
349 | | IPAddress VrrpLayer::getIPAddressFromData(uint8_t* data) const |
350 | 27.2k | { |
351 | 27.2k | if (getAddressType() == IPAddress::IPv4AddressType) |
352 | 27.2k | { |
353 | 27.2k | return IPv4Address(*reinterpret_cast<const uint32_t*>(data)); |
354 | 27.2k | } |
355 | | |
356 | 25 | return IPv6Address(data); |
357 | 27.2k | } |
358 | | |
359 | | bool VrrpLayer::isIPAddressValid(IPAddress& ipAddress) const |
360 | 0 | { |
361 | 0 | if (ipAddress.isIPv6() && (getProtocol() != VRRPv3)) |
362 | 0 | { |
363 | 0 | PCPP_LOG_ERROR("Only VRRPv3 support IPv6 virtual address"); |
364 | 0 | return false; |
365 | 0 | } |
366 | 0 | if (ipAddress.getType() != getAddressType()) |
367 | 0 | { |
368 | 0 | PCPP_LOG_ERROR("IP address version is not equal to layer's"); |
369 | 0 | return false; |
370 | 0 | } |
371 | | |
372 | 0 | return true; |
373 | 0 | } |
374 | | |
375 | | IPAddress::AddressType VrrpLayer::getAddressType() const |
376 | 59.7k | { |
377 | 59.7k | return m_AddressType; |
378 | 59.7k | } |
379 | | |
380 | | void VrrpLayer::setAddressType(IPAddress::AddressType addressType) |
381 | 0 | { |
382 | 0 | m_AddressType = addressType; |
383 | 0 | } |
384 | | |
385 | | // -------- Class Vrrpv2Layer ----------------- |
386 | | |
387 | | VrrpV2Layer::VrrpV2Layer(uint8_t virtualRouterId, uint8_t priority, uint8_t advInt, uint8_t authType) |
388 | 0 | : VrrpLayer(VRRPv2, virtualRouterId, priority) |
389 | 0 | { |
390 | 0 | setAdvInt(advInt); |
391 | 0 | setAuthType(authType); |
392 | 0 | } |
393 | | |
394 | | VrrpV2Layer::VrrpAuthType VrrpV2Layer::getAuthTypeAsEnum() const |
395 | 802 | { |
396 | 802 | auto authType = getAuthType(); |
397 | 802 | if (authType > 3) |
398 | 717 | { |
399 | 717 | return VrrpAuthType::Other; |
400 | 717 | } |
401 | | |
402 | 85 | return static_cast<VrrpAuthType>(authType); |
403 | 802 | } |
404 | | |
405 | | uint8_t VrrpV2Layer::getAdvInt() const |
406 | 802 | { |
407 | 802 | uint16_t authAdvInt = getVrrpHeader()->authTypeAdvInt; |
408 | 802 | auto authAdvIntPtr = reinterpret_cast<vrrpv2_auth_adv*>(&authAdvInt); |
409 | 802 | return authAdvIntPtr->advInt; |
410 | 802 | } |
411 | | |
412 | | void VrrpV2Layer::setAdvInt(uint8_t advInt) |
413 | 0 | { |
414 | 0 | auto authAdvIntPtr = reinterpret_cast<vrrpv2_auth_adv*>(&getVrrpHeader()->authTypeAdvInt); |
415 | 0 | authAdvIntPtr->advInt = advInt; |
416 | 0 | } |
417 | | |
418 | | uint8_t VrrpV2Layer::getAuthType() const |
419 | 802 | { |
420 | 802 | uint16_t authAdvInt = getVrrpHeader()->authTypeAdvInt; |
421 | 802 | auto* authAdvIntPtr = reinterpret_cast<vrrpv2_auth_adv*>(&authAdvInt); |
422 | 802 | return authAdvIntPtr->authType; |
423 | 802 | } |
424 | | |
425 | | void VrrpV2Layer::setAuthType(uint8_t authType) |
426 | 0 | { |
427 | 0 | auto authAdvIntPtr = reinterpret_cast<vrrpv2_auth_adv*>(&getVrrpHeader()->authTypeAdvInt); |
428 | 0 | authAdvIntPtr->authType = authType; |
429 | 0 | } |
430 | | |
431 | | uint16_t VrrpV2Layer::calculateChecksum() const |
432 | 1.60k | { |
433 | 1.60k | if ((getData() == nullptr) || (getDataLen() == 0)) |
434 | 0 | { |
435 | 0 | return 0; |
436 | 0 | } |
437 | | |
438 | 1.60k | auto vrrpHeader = getVrrpHeader(); |
439 | 1.60k | ScalarBuffer<uint16_t> buffer = {}; |
440 | 1.60k | buffer.buffer = reinterpret_cast<uint16_t*>(vrrpHeader); |
441 | 1.60k | buffer.len = getHeaderLen(); |
442 | | |
443 | 1.60k | uint16_t currChecksumValue = vrrpHeader->checksum; |
444 | 1.60k | vrrpHeader->checksum = 0; |
445 | 1.60k | uint16_t checksum = computeChecksum(&buffer, 1); |
446 | 1.60k | vrrpHeader->checksum = currChecksumValue; |
447 | | |
448 | 1.60k | return checksum; |
449 | 1.60k | } |
450 | | |
451 | | // -------- Class Vrrpv3Layer ----------------- |
452 | | |
453 | | VrrpV3Layer::VrrpV3Layer(IPAddress::AddressType addressType, uint8_t virtualRouterId, uint8_t priority, |
454 | | uint16_t maxAdvInt) |
455 | 0 | : VrrpLayer(VRRPv3, virtualRouterId, priority) |
456 | 0 | { |
457 | 0 | setAddressType(addressType); |
458 | 0 | setMaxAdvInt(maxAdvInt); |
459 | 0 | } |
460 | | |
461 | | uint16_t VrrpV3Layer::getMaxAdvInt() const |
462 | 1.44k | { |
463 | 1.44k | uint16_t authAdvInt = getVrrpHeader()->authTypeAdvInt; |
464 | 1.44k | auto rsvdAdv = reinterpret_cast<vrrpv3_rsvd_adv*>(&authAdvInt); |
465 | 1.44k | return be16toh(rsvdAdv->maxAdvInt); |
466 | 1.44k | } |
467 | | |
468 | | void VrrpV3Layer::setMaxAdvInt(uint16_t maxAdvInt) |
469 | 0 | { |
470 | 0 | if (maxAdvInt > 0xfff) |
471 | 0 | { |
472 | 0 | throw std::invalid_argument("maxAdvInt must not exceed 12 bits length"); |
473 | 0 | } |
474 | 0 | auto rsvdAdv = reinterpret_cast<vrrpv3_rsvd_adv*>(&getVrrpHeader()->authTypeAdvInt); |
475 | 0 | rsvdAdv->maxAdvInt = htobe16(maxAdvInt); |
476 | 0 | } |
477 | | |
478 | | uint16_t VrrpV3Layer::calculateChecksum() const |
479 | 2.88k | { |
480 | 2.88k | auto* ipLayer = getAttachedPacket()->getLayerOfType<pcpp::IPLayer>(); |
481 | 2.88k | if (ipLayer == nullptr) |
482 | 0 | { |
483 | 0 | PCPP_LOG_ERROR("Calculate checksum failed, for can not get IPLayer" << ""); |
484 | 0 | return 0; |
485 | 0 | } |
486 | | |
487 | 2.88k | auto vrrpHeader = getVrrpHeader(); |
488 | 2.88k | uint16_t currChecksumValue = vrrpHeader->checksum; |
489 | 2.88k | vrrpHeader->checksum = 0; |
490 | | |
491 | 2.88k | pcpp::IPAddress srcIPAddr = ipLayer->getSrcIPAddress(); |
492 | 2.88k | pcpp::IPAddress dstIPAddr = ipLayer->getDstIPAddress(); |
493 | 2.88k | uint16_t checksum; |
494 | 2.88k | if (getAddressType() == IPAddress::IPv4AddressType) |
495 | 1.24k | { |
496 | 1.24k | checksum = computePseudoHdrChecksum((uint8_t*)vrrpHeader, getDataLen(), IPAddress::IPv4AddressType, |
497 | 1.24k | PACKETPP_IPPROTO_VRRP, srcIPAddr, dstIPAddr); |
498 | 1.24k | } |
499 | 1.64k | else |
500 | 1.64k | { |
501 | 1.64k | checksum = computePseudoHdrChecksum((uint8_t*)vrrpHeader, getDataLen(), IPAddress::IPv6AddressType, |
502 | 1.64k | PACKETPP_IPPROTO_VRRP, srcIPAddr, dstIPAddr); |
503 | 1.64k | } |
504 | | |
505 | 2.88k | vrrpHeader->checksum = currChecksumValue; |
506 | | |
507 | 2.88k | return checksum; |
508 | 2.88k | } |
509 | | } // namespace pcpp |