Skip to content

Commit

Permalink
feat: add helper methods to compute UDP checksum
Browse files Browse the repository at this point in the history
  • Loading branch information
jpcsmith committed Nov 29, 2023
1 parent 890a4e4 commit b92b55f
Showing 1 changed file with 44 additions and 9 deletions.
53 changes: 44 additions & 9 deletions crates/scion/src/udp/datagram.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,59 @@
#![allow(unused)]
use bytes::{Buf, Bytes};
use scion_proto::{packet::ByEndpoint, wire_encoding::WireDecode};
use scion_proto::{
packet::{AddressHeader, ByEndpoint, ChecksumDigest},
wire_encoding::WireDecode,
};

#[derive(Debug, thiserror::Error)]
pub(super) enum UdpDecodeError {
#[error("datagram is empty or was truncated")]
DatagramEmptyOrTruncated,
}

/// Scion UDP datagram
///
/// The SCION UDP datagram format includes a checksum that is calculated based on
/// the [RFC].
///
/// [RFC]: https://www.ietf.org/archive/id/draft-dekater-scion-dataplane-00.html
#[derive(Debug, Default)]
pub(super) struct UdpDatagram {
/// The source and destination ports
pub port: ByEndpoint<u16>,
/// The length of the header and payload
pub length: u16,
/// SCION checksum, computed with a pseudo-header
pub checksum: u16,
/// The UDP payload
pub payload: Bytes,
}

impl UdpDatagram {
const HEADER_LEN: usize = 16;
}
const PROTOCOL_NUMBER: u8 = 17;
const HEADER_LEN: usize = 8;

#[derive(Debug, thiserror::Error)]
pub(super) enum UdpDecodeError {
#[error("datagram is empty or was truncated")]
DatagramEmptyOrTruncated,
/// Compute the checksum for this datagram using the provided address header.
pub fn calculate_checksum(&self, address_header: &AddressHeader) -> u16 {
ChecksumDigest::with_pseudoheader(address_header, Self::PROTOCOL_NUMBER, self.length.into())
.add_u16(self.port.source)
.add_u16(self.port.destination)
.add_u16(self.length)
.add_u16(self.checksum)
.add_slice(&self.payload)
.checksum()
}

/// Returns true if the checksum successfully verifies, otherwise false.
pub fn verify_checksum(&self, address_header: &AddressHeader) -> bool {
self.calculate_checksum(address_header) == 0
}

/// Clears then sets the checksum to the value returned by [`Self::calculate_checksum()`].
pub fn set_checksum(&mut self, address_header: &AddressHeader) {
self.checksum = 0;
self.checksum = self.calculate_checksum(address_header);
}
}

impl<T> WireDecode<T> for UdpDatagram
Expand All @@ -34,8 +71,6 @@ where
let destination = data.get_u16();
let length = data.get_u16();
let checksum = data.get_u16();
// TODO(jsmith): Check for additional verifications to be done on these fields
// TODO(jsmith): Determine whether we should check the checksum

let payload_length = usize::from(length) - Self::HEADER_LEN;
if payload_length <= data.remaining() {
Expand Down

0 comments on commit b92b55f

Please sign in to comment.