OpenVPN 3 Core Library
Loading...
Searching...
No Matches
csum.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// IP checksum based on Linux kernel implementation
13
14#pragma once
15
16#include <cstdint>
17
21
23
24inline std::uint16_t fold(std::uint32_t sum)
25{
26 sum = (sum >> 16) + (sum & 0xffff);
27 sum += (sum >> 16);
28 return static_cast<uint16_t>(sum & 0x0000FFFF);
29}
30
31inline std::uint16_t cfold(const std::uint32_t sum)
32{
33 return static_cast<uint16_t>(~fold(sum));
34}
35
36inline std::uint32_t unfold(const std::uint16_t sum)
37{
38 return sum;
39}
40
41inline std::uint32_t cunfold(const std::uint16_t sum)
42{
43 return ~unfold(sum);
44}
45
46inline std::uint32_t compute(const std::uint8_t *buf, size_t len)
47{
48 std::uint32_t result = 0;
49
50 if (!len)
51 return 0;
52
53 const bool odd = size_t(buf) & 1;
54 if (odd)
55 {
56#ifdef OPENVPN_LITTLE_ENDIAN
57 result += (*buf << 8);
58#else
59 result = *buf;
60#endif
61 len--;
62 buf++;
63 }
64
65 if (len >= 2)
66 {
67 if (size_t(buf) & 2)
68 {
69 result += *(std::uint16_t *)buf;
70 len -= 2;
71 buf += 2;
72 }
73 if (len >= 4)
74 {
75 const uint8_t *end = buf + (len & ~3);
76 std::uint32_t carry = 0;
77 do
78 {
79 std::uint32_t w = *(std::uint32_t *)buf;
80 buf += 4;
81 result += carry;
82 result += w;
83 carry = (w > result);
84 } while (buf < end);
85 result += carry;
86 result = (result & 0xffff) + (result >> 16);
87 }
88 if (len & 2)
89 {
90 result += *(std::uint16_t *)buf;
91 buf += 2;
92 }
93 }
94 if (len & 1)
95 {
96#ifdef OPENVPN_LITTLE_ENDIAN
97 result += *buf;
98#else
99 result += (*buf << 8);
100#endif
101 }
102 result = fold(result);
103 if (odd)
104 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
105 return result;
106}
107
108inline std::uint32_t compute(const void *buf, const size_t len)
109{
110 return compute((const std::uint8_t *)buf, len);
111}
112
113inline std::uint32_t partial(const void *buf, const size_t len, const std::uint32_t sum)
114{
115 std::uint32_t result = compute(buf, len);
116
117 /* add in old sum, and carry.. */
118 result += sum;
119 if (sum > result)
120 result += 1;
121 return result;
122}
123
124inline std::uint32_t diff16(const std::uint32_t *old,
125 const std::uint32_t *new_,
126 const std::uint32_t oldsum)
127{
128 // clang-format off
129 std::uint32_t diff[8] = {~old[0], ~old[1], ~old[2], ~old[3],
130 new_[0], new_[1], new_[2], new_[3]};
131 return partial(diff, sizeof(diff), oldsum);
132 // clang-format on
133}
134
135inline std::uint32_t diff16(const std::uint8_t *old,
136 const std::uint8_t *new_,
137 const std::uint32_t oldsum)
138{
139 return diff16((const std::uint32_t *)old, (const std::uint32_t *)new_, oldsum);
140}
141
142inline std::uint32_t diff4(const std::uint32_t old,
143 const std::uint32_t new_,
144 const std::uint32_t oldsum)
145{
146 std::uint32_t diff[2] = {~old, new_};
147 return partial(diff, sizeof(diff), oldsum);
148}
149
150inline std::uint32_t diff2(const std::uint16_t old,
151 const std::uint16_t new_,
152 const std::uint32_t oldsum)
153{
154 std::uint16_t diff[2] = {std::uint16_t(~old), new_};
155 return partial(diff, sizeof(diff), oldsum);
156}
157
158inline std::uint16_t checksum(const void *data, const size_t size)
159{
160 return cfold(compute(data, size));
161}
162} // namespace openvpn::IPChecksum
std::uint32_t diff16(const std::uint32_t *old, const std::uint32_t *new_, const std::uint32_t oldsum)
Definition csum.hpp:124
std::uint32_t compute(const std::uint8_t *buf, size_t len)
Definition csum.hpp:46
std::uint32_t partial(const void *buf, const size_t len, const std::uint32_t sum)
Definition csum.hpp:113
std::uint32_t cunfold(const std::uint16_t sum)
Definition csum.hpp:41
std::uint16_t fold(std::uint32_t sum)
Definition csum.hpp:24
std::uint32_t unfold(const std::uint16_t sum)
Definition csum.hpp:36
std::uint16_t cfold(const std::uint32_t sum)
Definition csum.hpp:31
std::uint32_t diff2(const std::uint16_t old, const std::uint16_t new_, const std::uint32_t oldsum)
Definition csum.hpp:150
std::uint16_t checksum(const void *data, const size_t size)
Definition csum.hpp:158
std::uint32_t diff4(const std::uint32_t old, const std::uint32_t new_, const std::uint32_t oldsum)
Definition csum.hpp:142