Skip to content

Commit 1ff0477

Browse files
net: Added checksum_adjust to partial adjust checksum
1 parent cc83c56 commit 1ff0477

3 files changed

Lines changed: 97 additions & 0 deletions

File tree

api/net/inet_common.hpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,38 @@ namespace net {
5353
return checksum(0, data, len);
5454
}
5555

56+
/**
57+
* @brief Adjust the checksum according to the difference between old and new data.
58+
*
59+
* @note Only supports even offsets (length needs to be even)
60+
* See: https://tools.ietf.org/html/rfc3022#page-9 (4.2) Checksum Adjustment
61+
*
62+
* @param chksum Pointer to the checksum to adjust
63+
* @param odata The old data
64+
* @param[in] olen The length of the old data
65+
* @param ndata The new data
66+
* @param[in] nlen The length of the new data
67+
*/
68+
void checksum_adjust(uint8_t* chksum, const void* odata,
69+
int olen, const void* ndata, int nlen);
70+
71+
/**
72+
* @brief Helper function for adjusting checksum when only an object is changed,
73+
* e.g. IP address in a packet header
74+
*
75+
* @param chksum Pointer to the checksum to adjust
76+
* @param[in] old_obj The old object
77+
* @param[in] new_obj The new object
78+
*
79+
* @tparam T The type of object
80+
*/
81+
template <typename T>
82+
void checksum_adjust(uint16_t* chksum, const T* old_obj, const T* new_obj)
83+
{
84+
static_assert(sizeof(T) % 2 == 0, "Checksum adjust only supports even lengths");
85+
checksum_adjust(reinterpret_cast<uint8_t*>(chksum), old_obj, sizeof(T), new_obj, sizeof(T));
86+
}
87+
5688
// View a packet differently based on context
5789
template <typename T, typename Packet>
5890
inline auto view_packet_as(Packet packet) noexcept {

src/net/inet_common.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,34 @@ uint16_t checksum(uint32_t tsum, const void* data, size_t length) noexcept
7373
return ~a16;
7474
}
7575

76+
// Taken from https://tools.ietf.org/html/rfc3022#page-9
77+
void checksum_adjust(uint8_t* chksum, const void* odata,
78+
int olen, const void* ndata, int nlen)
79+
{
80+
Expects(olen % 2 == 0 and nlen % 2 == 0);
81+
82+
const auto* optr = reinterpret_cast<const uint8_t*>(odata);
83+
const auto* nptr = reinterpret_cast<const uint8_t*>(ndata);
84+
85+
int32_t x, o32, n32;
86+
x=chksum[0]*256+chksum[1];
87+
x=~x & 0xFFFF;
88+
while (olen)
89+
{
90+
o32=optr[0]*256+optr[1]; optr+=2;
91+
x-=o32 & 0xffff;
92+
if (x<=0) { x--; x&=0xffff; }
93+
olen-=2;
94+
}
95+
while (nlen)
96+
{
97+
n32=nptr[0]*256+nptr[1]; nptr+=2;
98+
x+=n32 & 0xffff;
99+
if (x & 0x10000) { x++; x&=0xffff; }
100+
nlen-=2;
101+
}
102+
x=~x & 0xFFFF;
103+
chksum[0]=x/256; chksum[1]=x & 0xff;
104+
}
105+
76106
} //< namespace net

test/net/unit/checksum.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,38 @@ CASE("Verify IP checksum using buffers of various lengths")
7070
EXPECT(net::checksum(buffer, sizeof(buffer)) == 0);
7171
}
7272
}
73+
74+
CASE("Verify adjusting checksum")
75+
{
76+
char buffer[2048];
77+
for (size_t j = 0; j < 32; j++)
78+
{
79+
buffer[0] = 0;
80+
buffer[1] = 0;
81+
for (size_t i = 2; i < sizeof(buffer); i++)
82+
buffer[i] = rand() & 0xff;
83+
84+
// Set checksum
85+
auto csum = net::checksum(buffer, sizeof(buffer));
86+
memcpy(buffer, &csum, sizeof(csum));
87+
88+
// Create some random data
89+
char rndm[512];
90+
for (size_t i = 0; i < sizeof(rndm); i++)
91+
rndm[i] = rand() & 0xff;
92+
93+
// A fixed point inside the buffer
94+
const size_t N = sizeof(buffer) / 2;
95+
96+
// Adjust the checksum
97+
net::checksum_adjust((uint8_t*)buffer, &buffer[N], sizeof(rndm), rndm, sizeof(rndm));
98+
99+
// Make sure to add the random data at the same place
100+
memcpy(&buffer[N], rndm, sizeof(rndm));
101+
102+
// Checksum the buffer (without the csum)
103+
csum = net::checksum(&buffer[2], sizeof(buffer)-2);
104+
105+
EXPECT(csum == *(uint16_t*)buffer);
106+
}
107+
}

0 commit comments

Comments
 (0)