Skip to content

Commit

Permalink
util: compute_generic_checksum()
Browse files Browse the repository at this point in the history
This commit add a helper function for checksumming data which is needed
in hvac frames.

History of this function is complicated and described below... :)

When writing a rust function I was basing on two current implementations:
Python:
https://github.com/liaan/broadlink_ac_mqtt/blob/eb26e2b2eafabc58d55680abd911afeae523f592/broadlink_ac_mqtt/classes/broadlink/ac_db.py#L876
and a Swift one:
https://github.com/makleso6/ACFreedom/blob/25f36bfeac0ebaca7db2def8507e37f37cfbac7c/Sources/ACFreedom/DeviceController.swift#L241

Thanks to stackoverflow (https://stackoverflow.com/a/57172592) I ended
up using chunks_exact() and got a working implementation.
But when searching for example code using this, I came across Microsoft
implementation:
https://github.com/microsoft/demikernel/blob/9667ad81546421dbf709330e9e21ed8e187cb816/src/rust/inetstack/protocols/mod.rs#L40

I liked this very much so I only adjusted this function to our needs.

After all this I realized that this function is just the UDP checksum
function. So we may consider using eg. following crates for this:
https://crates.io/crates/pnet_packet
https://crates.io/crates/etherparse
Anyway - it's a thing to consider if adding the dependency for using a
single checksum function is worth it...
For now I am just commiting this implementation.

The commit also fixes lack of new line at EOF.
  • Loading branch information
manio committed Sep 3, 2023
1 parent 9280503 commit b491881
Showing 1 changed file with 26 additions and 1 deletion.
27 changes: 26 additions & 1 deletion src/network/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::{
UdpSocket,
},
time::Duration,
slice::ChunksExact,
};

/// Computes the checksum of a slice of bytes.
Expand All @@ -24,6 +25,30 @@ pub fn checksum(data: &[u8]) -> u16 {
return sum as u16;
}

/// Computes the generic checksum of a bytes array.
///
/// This iterates all 16-bit array elements, summing
/// the values into a 32-bit variable. This functions
/// paddies with zero an octet at the end (if necessary)
/// to turn into a 16-bit element.
pub fn compute_generic_checksum(buf: &[u8]) -> u16 {
let mut state: u32 = 0xFFFF;

let mut chunks_iter: ChunksExact<u8> = buf.chunks_exact(2);
while let Some(chunk) = chunks_iter.next() {
state += u16::from_le_bytes([chunk[0], chunk[1]]) as u32;
}

if let Some(&b) = chunks_iter.remainder().get(0) {
state += u16::from_le_bytes([b, 0]) as u32;
}

state = (state >> 16) + (state & 0xffff);
state = !state & 0xffff;

state as u16
}

/// Returns the first available non-local address or the passed IP, if present.
pub fn local_ip_or(ip: Option<Ipv4Addr>) -> IpAddr {
return match ip {
Expand Down Expand Up @@ -107,4 +132,4 @@ pub fn reverse_mac(mac_flipped: [u8; 6]) -> [u8; 6] {
}

return mac;
}
}

0 comments on commit b491881

Please sign in to comment.