use core::fmt::Debug; use crc::{Crc, CRC_16_IBM_SDLC}; use labrador_ldpc::decoder::DecodeFrom; use crate::{ buffer::{Buffer, BufferOverflow}, error::{CommentError, DecodeError, DigipeatError, EncodeError, PacketRouteAppendError}, identity::Identity, interleaver, ldpc, utf8, whisker::{ Arbitrary, Comment, Destination, Gps, Identification, NodeInfo, PastHop, Route, RouteHop, Timestamp, ValidatedWhiskerIter, Whisker, WhiskerIter, COMMENT_TYPE, }, whitener, }; const X25: Crc<u16> = Crc::<u16>::new(&CRC_16_IBM_SDLC); macro_rules! uniq_whisker { ($t:meta) => { ::paste::paste! { pub fn [<$t:snake:lower>](&self) -> Option<$t> { self.iter().find_map(|w| match w { Whisker::$t(x) => Some(x), _ => None, }) } pub fn [<add_ $t:snake:lower>](&mut self, w: $t) -> Result<(), EncodeError> { if self.[<$t:snake:lower>]().is_some() { return Err(EncodeError::DuplicateData); } try_lock(&mut self.buf, |data| { let mut buf = [0; 256]; // safe to unwrap since we know we have enough space let out = w.encode(&mut buf).unwrap(); data.try_push(crate::whisker::[<$t:snake:upper _TYPE>]).ok().ok_or(EncodeError::CatsOverflow)?; data.try_extend_from_slice(out).ok().ok_or(EncodeError::CatsOverflow)?; Ok(()) })?; Ok(()) } pub fn [<clear_ $t:snake:lower>](&mut self) { self.clear_by_type(crate::whisker::[<$t:snake:upper _TYPE>], false); } } }; } macro_rules! poly_whisker { ($t: meta) => { ::paste::paste! { pub fn [<$t:lower _iter>](&self) -> core::iter::FilterMap<ValidatedWhiskerIter, fn(Whisker) -> Option<$t>> { fn filt(w: Whisker) -> Option<$t> { match w { Whisker::$t(x) => Some(x), _ => None } } self.iter().filter_map(filt) } pub fn [<add_ $t:lower>](&mut self, w: $t) -> Result<(), EncodeError> { try_lock(&mut self.buf, |data| { let mut buf = [0; 256]; // safe to unwrap since we know we have enough space let out = w.encode(&mut buf).unwrap(); data.try_push(crate::whisker::[<$t:upper _TYPE>]).ok().ok_or(EncodeError::CatsOverflow)?; data.try_extend_from_slice(out).ok().ok_or(EncodeError::CatsOverflow)?; Ok(()) })?; Ok(()) } pub fn [<clear_ $t:lower>](&mut self) { self.clear_by_type(crate::whisker::[<$t:upper _TYPE>], true); } } }; } /// N is the maximum packet size we can handle /// Panics if N >= 8191 pub struct Packet<'a, const N: usize> { buf: Buffer<'a, N>, } impl<'a, const N: usize> Packet<'a, N> { pub fn new(buf: &'a mut [u8; N]) -> Self { Self { buf: buf.into() } } pub fn clone_backing<'b>(&self, buf: &'b mut [u8; N]) -> Packet<'b, N> { Packet { buf: self.buf.clone_backing(buf), } } /// Expects bytes in the `buf` /// `buf` is used as the backing buffer for the Packet pub fn decode(buf: Buffer<'a, N>) -> Result<Self, DecodeError> { assert!(N <= 8191); // validate the data for w in WhiskerIter::new(&buf) { w?; } let comment_iter = WhiskerIter::new(&buf) .filter_map(|w| match w.unwrap() { Whisker::Comment(c) => Some(c.internal_data().clone()), _ => None, }) .flatten(); if !utf8::validate(comment_iter) { return Err(DecodeError::InvalidComment); } Ok(Self { buf }) } pub fn encode(&self) -> &[u8] { &self.buf } /// Directly after the CRC block in The Pipeline pub fn semi_encode(mut self) -> Result<Buffer<'a, N>, (EncodeError, Self)> { let crc = X25.checksum(&self.buf).to_le_bytes(); let res: Result<(), BufferOverflow> = try_lock(&mut self.buf, |data| { data.try_push(crc[0])?; data.try_push(crc[1])?; Ok(()) }); match res { Ok(()) => Ok(self.buf), Err(_) => Err((EncodeError::CatsOverflow, self)), } } /// Directly after the CRC block in The Pipeline /// Expects bytes in the `buf` /// `buf` is used as the backing buffer for the Packet pub fn semi_decode(mut buf: Buffer<'a, N>) -> Result<Self, DecodeError> { let crc1 = buf.pop().ok_or(DecodeError::UnexpectedEndOfInput)?; let crc0 = buf.pop().ok_or(DecodeError::UnexpectedEndOfInput)?; let crc_expected = u16::from_le_bytes([crc0, crc1]); let crc_actual = X25.checksum(&buf); if crc_expected != crc_actual { return Err(DecodeError::CrcMismatch); } Self::decode(buf) } /// Encodes packet for transmission on the air. /// Includes the data length L, but does not include the preamble or sync word. pub fn fully_encode<const M: usize>(self, out: &mut Buffer<M>) -> Result<(), EncodeError> { let mut data = self.semi_encode().map_err(|(err, _)| err)?; whitener::whiten(&mut data); ldpc::encode(&mut data)?; // safe to unwrap - length must be below 8191 out.try_extend_from_slice(&u16::try_from(data.len()).unwrap().to_le_bytes()) .map_err(|_| EncodeError::CatsOverflow)?; interleaver::interleave(&data, out)?; Ok(()) } /// Decodes packet that was received over the air. /// Packet shouldn't have preamble, sync word, or data langth L. /// Expects bytes in `data` /// `buf` is used as the backing buffer for the Packet pub fn fully_decode(data: &[u8], buf: &'a mut [u8; N]) -> Result<Self, DecodeError> { let mut buf = Buffer::new_empty(buf); interleaver::uninterleave(data, &mut buf).map_err(|_| DecodeError::Overflow)?; ldpc::decode(&mut buf).ok_or(DecodeError::LdpcError)?; whitener::whiten(&mut buf); Self::semi_decode(buf) } /// Expects soft bits in `data`. Bits should be LLR, with positive numbers more likely to be 0. /// Returns `DecodeError::Overflow` if `M` is less than `data.len()`. pub fn fully_decode_soft<const M: usize, T: DecodeFrom>( data: &mut [T], buf: &'a mut [u8; N], ) -> Result<Self, DecodeError> { let mut out = [T::zero(); M]; let mut out = Buffer::new_empty(&mut out); interleaver::uninterleave_soft(data, &mut out).map_err(|_| DecodeError::Overflow)?; let mut buf = Buffer::new_empty(buf); ldpc::decode_soft(&mut out, &mut buf).ok_or(DecodeError::LdpcError)?; whitener::whiten(&mut buf); Self::semi_decode(buf) } pub fn iter(&self) -> ValidatedWhiskerIter { ValidatedWhiskerIter::new(&self.buf) } uniq_whisker!(Identification); uniq_whisker!(Timestamp); uniq_whisker!(Gps); uniq_whisker!(Route); uniq_whisker!(NodeInfo); poly_whisker!(Destination); poly_whisker!(Arbitrary); pub fn comment<'b>(&self, buf: &'b mut [u8]) -> Result<&'b str, CommentError> { let iter = self.iter().filter_map(|w| match w { Whisker::Comment(c) => Some(c), _ => None, }); let mut i = 0; let mut has_comment = false; for c in iter { has_comment = true; let data = c.internal_data(); buf.get_mut(i..(i + data.len())) .ok_or(CommentError::BufferOverflow)? .copy_from_slice(data); i += data.len(); } if !has_comment { return Err(CommentError::NoComment); } // Safe to unwrap since the comment was pre-validated Ok(core::str::from_utf8(&buf[0..i]).unwrap()) } pub fn add_comment(&mut self, comment: &str) -> Result<(), EncodeError> { if self.iter().any(|w| matches!(w, Whisker::Comment(_))) { // we already have a comment return Err(EncodeError::DuplicateData); } try_lock(&mut self.buf, |data| { let mut comment = comment.as_bytes(); while comment.len() > 255 { let c = Comment::new(&comment[0..255]).unwrap(); let mut buf = [0; 256]; let out = c.encode(&mut buf).unwrap(); data.try_push(COMMENT_TYPE) .map_err(|_| EncodeError::CatsOverflow)?; data.try_extend_from_slice(out) .map_err(|_| EncodeError::CatsOverflow)?; comment = &comment[255..]; } let c = Comment::new(comment).unwrap(); let mut buf = [0; 256]; let out = c.encode(&mut buf).unwrap(); data.try_push(COMMENT_TYPE) .map_err(|_| EncodeError::CatsOverflow)?; data.try_extend_from_slice(out) .map_err(|_| EncodeError::CatsOverflow)?; Ok(()) })?; Ok(()) } pub fn clear_comment(&mut self) { self.clear_by_type(COMMENT_TYPE, true); } /// Given the callsign and ssid of a node, should it digipeat this packet? /// Takes into account things such as if we've digipeated it already, the max hops, etc. pub fn should_digipeat(&self, identity: Identity) -> Result<(), DigipeatError> { let route = match self.route() { Some(x) => x, None => { return Err(DigipeatError::NoRoute); } }; if let Some(ident) = self.identification() { if &ident.callsign == identity.callsign() && ident.ssid == identity.ssid() { return Err(DigipeatError::Us); } } let max_hops: usize = route.max_hops.into(); let cur_hops = route .iter() .filter(|r| match r { RouteHop::Internet => false, RouteHop::Past(_) => true, RouteHop::Future(_) => false, }) .count(); if max_hops <= cur_hops { return Err(DigipeatError::MaxHops); } let already_digipeated = route.iter().any(|r| match r { RouteHop::Internet => false, RouteHop::Past(past_hop) => past_hop.identity() == identity, RouteHop::Future(_) => false, }); if already_digipeated { return Err(DigipeatError::AlreadyDigipeated); } let next_node = route.iter().find_map(|r| match r { RouteHop::Future(x) => Some(x), _ => None, }); match next_node { Some(ident) if ident != identity => Err(DigipeatError::SetDestiny), _ => Ok(()), } } /// Note that if this fails due to a CATS overflow, it will wipe the route off of the packet pub fn append_to_route( &mut self, callsign: &str, ssid: u8, rssi: Option<f64>, ) -> Result<(), PacketRouteAppendError> { let mut route = self.route().ok_or(PacketRouteAppendError::NoRouteWhisker)?; route .append_hop(PastHop::new(Identity::new(callsign, ssid), rssi)) .map_err(|error| PacketRouteAppendError::Route { error })?; self.clear_route(); self.add_route(route) .map_err(|_| PacketRouteAppendError::PacketOverflow)?; Ok(()) } fn clear_by_type(&mut self, whisker_type: u8, all: bool) { let mut i = 0; while i < self.buf.len() { let t = self.buf[i]; let step = usize::from(self.buf[i + 1]) + 2; if t == whisker_type { self.buf.drain(i, i + step); if !all { return; } } else { i += step; } } } } impl<const N: usize> Debug for Packet<'_, N> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_list() .entries(ValidatedWhiskerIter::new(&self.buf)) .finish() } } // if the function returns an error, we roll back the array // by rolling it back, we really just pop bytes off the end until the length matches fn try_lock<'a, const N: usize, T, E, F: Fn(&mut Buffer<'a, N>) -> Result<T, E>>( buf: &mut Buffer<'a, N>, f: F, ) -> Result<T, E> { let len = buf.len(); match f(buf) { Ok(x) => Ok(x), Err(e) => { buf.truncate(len); Err(e) } } } #[cfg(test)] mod tests { use super::*; use crate::soft_bit::FromHardBit; use crate::whisker::NodeInfoBuilder; use arrayvec::ArrayString; use bitvec::{order::Msb0, view::BitView}; #[test] fn dest() { let d1 = Destination::new(false, 7, "CALL1", 23).unwrap(); let d2 = Destination::new(true, 23, "CALL2", 2).unwrap(); let mut buf = [0; 1024]; let mut packet: Packet<1024> = Packet::new(&mut buf); packet.add_destination(d1.clone()).unwrap(); packet.add_destination(d2.clone()).unwrap(); let mut dests = packet.destination_iter(); assert_eq!(d1, dests.next().unwrap()); assert_eq!(d2, dests.next().unwrap()); assert_eq!(None, dests.next()); } #[test] fn route_clear() { let mut buf = [0; 1024]; let mut p: Packet<1024> = Packet::new(&mut buf); p.add_identification(Identification::new("call", 43, 123).unwrap()) .unwrap(); let mut r = Route::new(8); r.push_internet().unwrap(); p.add_route(r).unwrap(); p.add_comment("This is a comment").unwrap(); p.clear_route(); assert_eq!( Identification::new("call", 43, 123).unwrap(), p.identification().unwrap() ); assert_eq!(None, p.route()); let mut buf = [0; 32]; assert_eq!("This is a comment", p.comment(&mut buf).unwrap()); } #[test] fn semi_e2e() { let comment = "Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker."; let mut buf = [0; 2048]; let mut packet = Packet::new(&mut buf); packet .add_identification(Identification { icon: 123, callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(), ssid: 43, }) .unwrap(); packet.add_comment(comment).unwrap(); let res = packet.add_identification(Identification { icon: 456, callsign: ArrayString::from("NOPE").unwrap(), ssid: 0, }); assert!(matches!(res, Err(EncodeError::DuplicateData))); let semi = packet.semi_encode().unwrap(); let packet2 = Packet::semi_decode(semi).unwrap(); assert_eq!( Identification { icon: 123, callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(), ssid: 43, }, packet2.identification().unwrap() ); let mut buf = [0; 1024]; assert_eq!(comment, packet2.comment(&mut buf).unwrap()); } #[test] fn full_e2e() { let comment = "Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker."; let mut buf = [0; 4096]; let mut packet = Packet::new(&mut buf); packet .add_identification(Identification { icon: 123, callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(), ssid: 43, }) .unwrap(); packet.add_comment(comment).unwrap(); let res = packet.add_identification(Identification { icon: 456, callsign: ArrayString::from("NOPE").unwrap(), ssid: 0, }); assert!(matches!(res, Err(EncodeError::DuplicateData))); let mut buf2 = [0; 4096]; let mut fully = Buffer::new_empty(&mut buf2); packet.fully_encode(&mut fully).unwrap(); fully[40] ^= 0x55; fully[844] ^= 0x7B; // exclude length let mut buf3 = [0; 8191]; let packet2: Packet<8191> = Packet::fully_decode(&fully[2..], &mut buf3).unwrap(); assert_eq!( Identification { icon: 123, callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(), ssid: 43, }, packet2.identification().unwrap() ); let mut buf = [0; 1024]; assert_eq!(comment, packet2.comment(&mut buf).unwrap()); } #[test] fn full_e2e_soft_decode() { let comment = "Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker."; let mut buf = [0; 4096]; let mut packet = Packet::new(&mut buf); packet .add_identification(Identification { icon: 123, callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(), ssid: 43, }) .unwrap(); packet.add_comment(comment).unwrap(); let res = packet.add_identification(Identification { icon: 456, callsign: ArrayString::from("NOPE").unwrap(), ssid: 0, }); assert!(matches!(res, Err(EncodeError::DuplicateData))); let mut buf2 = [0; 4096]; let mut fully = Buffer::new_empty(&mut buf2); packet.fully_encode(&mut fully).unwrap(); fully[40] ^= 0x55; fully[844] ^= 0x7B; let mut soft = [0.0; 8191 * 8]; let mut soft = Buffer::new_empty(&mut soft); for b in fully.view_bits::<Msb0>().iter() { soft.push(f32::from_hard_bit(*b)); } let soft = &mut soft[16..]; let mut buf3 = [0; 8191]; // exclude length let packet2: Packet<8191> = Packet::fully_decode_soft::<{ 8191 * 8 }, _>(soft, &mut buf3).unwrap(); assert_eq!( Identification { icon: 123, callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(), ssid: 43, }, packet2.identification().unwrap() ); let mut buf = [0; 1024]; assert_eq!(comment, packet2.comment(&mut buf).unwrap()); } #[test] fn node_info_e2e() { let mut buf = [0; 4096]; let mut packet = Packet::new(&mut buf); packet .add_node_info( NodeInfoBuilder::default() .hardware_id(0xBEEF) .software_id(0xBC) .uptime(2304) .antenna_height(5) .antenna_gain(3.0) .tx_power(30.0) .voltage(12.6) .xcvr_temperature(-15) .battery_charge(65.0) .build(), ) .unwrap(); let mut buf2 = [0; 4096]; let mut encoded = Buffer::new_empty(&mut buf2); packet.fully_encode(&mut encoded).unwrap(); let mut buf3 = [0; 4096]; let packet2 = Packet::fully_decode(&encoded[2..], &mut buf3).unwrap(); let node_info = packet2.node_info().unwrap(); assert_eq!(0xBEEF, node_info.hardware_id().unwrap()); assert_eq!(0xBC, node_info.software_id().unwrap()); assert_eq!(2304, node_info.uptime().unwrap()); assert_eq!(5, node_info.antenna_height().unwrap()); assert_eq!(3.0, node_info.antenna_gain().unwrap()); assert_eq!(30.0, node_info.tx_power().unwrap()); assert_eq!(12.6, node_info.voltage().unwrap()); assert_eq!(-15, node_info.xcvr_temperature().unwrap()); assert_eq!(64.70588235294117, node_info.battery_charge().unwrap()); } #[test] fn node_info_e2e_some_unpopulated() { let mut buf = [0; 4096]; let mut packet = Packet::new(&mut buf); packet .add_node_info( NodeInfoBuilder::default() .software_id(0xBC) .uptime(2304) .antenna_gain(3.0) .voltage(12.6) .xcvr_temperature(-15) .build(), ) .unwrap(); let mut buf2 = [0; 4096]; let mut encoded = Buffer::new_empty(&mut buf2); packet.fully_encode(&mut encoded).unwrap(); let mut buf3 = [0; 4096]; let packet2 = Packet::fully_decode(&encoded[2..], &mut buf3).unwrap(); let node_info = packet2.node_info().unwrap(); assert_eq!(None, node_info.hardware_id()); assert_eq!(0xBC, node_info.software_id().unwrap()); assert_eq!(2304, node_info.uptime().unwrap()); assert_eq!(None, node_info.antenna_height()); assert_eq!(3.0, node_info.antenna_gain().unwrap()); assert_eq!(None, node_info.tx_power()); assert_eq!(12.6, node_info.voltage().unwrap()); assert_eq!(-15, node_info.xcvr_temperature().unwrap()); assert_eq!(None, node_info.battery_charge()); } #[test] fn fully_decode_fuzz_tests() { let data = [ 112, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 74, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 114, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 10, 112, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 74, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 114, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 7, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 145, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 59, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 7, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 59, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 64, 0, 65, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 7, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 1, 0, 0, 10, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 64, 0, 65, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 7, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 1, 0, 0, 10, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 1, 2, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 0, 0, 96, 96, ]; let mut buf = [0; 1024]; let _ = Packet::<1024>::fully_decode(&data, &mut buf); } #[test] fn semi_decode_fuzz_tests() { let cases = [ &[ 42, 64, 64, 64, 229, 40, 64, 64, 0, 0, 173, 173, 173, 173, 173, 173, 173, 173, 64, 64, 0, 0, 173, 187, 187, 187, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 187, 187, 187, 101, 157, 138, 74, 101, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 187, 187, 187, 187, 187, 187, 187, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 187, 101, 157, 138, 74, 101, 157, 138, 106, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 173, 187, 187, 187, 101, 157, 138, 74, 101, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 173, 187, 187, 64, 187, 101, 157, 138, 74, 101, 157, 50, 138, 74, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 64, 64, 0, 0, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 187, 187, 187, 101, 157, 138, 74, 101, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 173, 187, 187, 187, 101, 157, 138, 74, 101, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 0, 0, 192, 192, 0, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 64, 64, 0, 0, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 187, 187, 187, 101, 157, 138, 74, 101, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 126, ][..], &[ 48, 5, 4, 255, 5, 5, 5, 5, 5, 5, 5, 37, 5, 7, 5, 5, 35, 5, 5, 5, 5, 4, 5, 7, 5, 5, 5, 5, 5, 5, 5, 5, 11, 126, 3, 101, 5, 3, 3, 96, 192, 128, 192, 192, ][..], ]; for data in cases { let mut buf = [0; 1024]; let mut buf = Buffer::new_empty(&mut buf); buf.extend(data); let _ = Packet::<1024>::semi_decode(buf); } } #[test] fn decode_fuzz_tests() { let cases = [&[4, 0, 0, 0][..], &[4, 5, 0, 0, 0, 10, 255, 255, 0, 0][..]]; for data in cases { let mut buf = [0; 1024]; let mut buf = Buffer::new_empty(&mut buf); buf.extend(data); let _ = Packet::<1024>::decode(buf); } } #[test] fn fully_decode_soft_fuzz_tests() { // When adding to this, don't forget to do the u8 -> i8 conversion let cases = [ &mut [ -39, -39, -39, -118, -58, -58, -58, -58, -89, -39, -118, -58, -58, -58, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, -58, -58, 127, 81, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, -86, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, -58, -58, 127, 81, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, -58, -58, 127, 81, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, -128, -128, ][..], &mut [ -73, -73, -73, -73, -75, -76, -73, -73, -73, -73, -73, -73, -73, -73, 73, 72, 72, 72, 72, 72, 72, 62, -73, -118, 120, 127, 127, 121, 127, 112, 127, 127, ], ]; for data in cases { let mut buf = [0; 1024]; let _ = Packet::<1024>::fully_decode_soft::<8192, i8>(data, &mut buf); } } }