Skip to content

Commit

Permalink
fix: correct checksum for misaligned slices
Browse files Browse the repository at this point in the history
  • Loading branch information
mlegner committed May 17, 2024
1 parent 0c3aba7 commit 9a54c48
Showing 1 changed file with 25 additions and 14 deletions.
39 changes: 25 additions & 14 deletions crates/scion-proto/src/packet/checksum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,30 +123,41 @@ impl ChecksumDigest {
return self;
}

// Converting to a &[u16] requires an even number of elements in the slice
let (data, initial_sum) = if data.len() % 2 == 0 {
(data, 0u32)
// Before converting to a `&[u16]` we need to make sure the slice is aligned.
let is_aligned = data.as_ptr().align_offset(2) == 0;
let (mut data, mut initial_sum) = if is_aligned {
(data, 0)
} else {
(
&data[..data.len() - 1],
// We want to zero pad the value, i.e., for slice where we pair the elements,
// we have [A, B], [C, D], ... [X, 0]. Since all the values are currently in
// memory in the order [A, B] storing [0, X] on a little endian architecture
// gets written as [X, 0] to memory. On big-endian this would get written as
// [0, X] so we swap it only on that big-endian architectures with to_le()
(data[data.len() - 1] as u16).to_le() as u32,
)
(&data[1..], data[0] as u32)
};

let ptr: *const u8 = data.as_ptr();

// Converting to a `&[u16]` requires an even number of elements in the slice.
if data.len() % 2 != 0 {
data = &data[..data.len() - 1];
// We want to zero pad the value, i.e., for slice where we pair the elements,
// we have [A, B], [C, D], ... [X, 0]. Since all the values are currently in
// memory in the order [A, B] storing [0, X] on a little endian architecture
// gets written as [X, 0] to memory. On big-endian this would get written as
// [0, X] so we swap it only on that big-endian architectures with to_le().
initial_sum += (data[data.len() - 1] as u16).to_le() as u32;
};

println!("{:?}", ptr);
let data_u16 = unsafe { slice::from_raw_parts(ptr as *const u16, data.len() / 2) };

let sum_with_overflow = data_u16
.iter()
.fold(initial_sum, |sum, value| sum + (*value as u32));

// Already incorporate the overflow, as it simplifies the endian conversion below
let sum = Self::fold_checksum(sum_with_overflow) as u16;
let mut sum = Self::fold_checksum(sum_with_overflow) as u16;

// If the original slice was not aligned, we need to swap the bytes to get the correct
// checksum.
if !is_aligned {
sum = sum.swap_bytes();
}

// The above sum is actually in big-endian but stored in big/little endian depending
// on the platform. If the platform is little endian, this call will swap the byte-order
Expand Down

0 comments on commit 9a54c48

Please sign in to comment.