diff --git a/Cargo.toml b/Cargo.toml index 0c380ab..74a3348 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,15 +15,13 @@ documentation = "https://docs.rs/geonetworking" [features] default = ["json", "validate"] # Enable serialization to and from JSON -json = ["dep:serde_json", "serde", "bytes/serde"] +json = ["dep:serde_json", "serde", "arbitrary-int/serde"] # Enable signature validation validate = ["ecdsa", "p256", "p384", "bp256", "bp384", "sha2", "sm2", "sm3"] [dependencies] -bitvec = { version = "1.0", default-features = false, features = ["alloc"] } -bytes = { version = "1.10", default-features = false } nom = { version = "7.1", default-features = false, features = ["alloc"] } -nom-bitvec = { package = "bitvec-nom2", version = "0.2.1" } +arbitrary-int = { version = "2.0.0" } num = { version = "0.4", default-features = false } num-traits = { version = "0.2", default-features = false } diff --git a/src/decode.rs b/src/decode.rs index cff43ca..e447ebb 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -2,25 +2,17 @@ extern crate alloc; #[cfg(not(feature = "validate"))] use alloc::vec; -use bitvec::prelude::*; +use arbitrary_int::{u10, u6}; use nom::{ bytes::streaming::take, - combinator::{into, map, map_res, peek}, + combinator::{into, map, map_res}, error::{ErrorKind, FromExternalError, ParseError}, - sequence::{pair, tuple}, - Needed, Parser, + ErrorConvert, Needed, Parser, }; -use nom_bitvec::BSlice; use num::{FromPrimitive, Integer}; -#[cfg(not(any(feature = "validate", test)))] -use num_traits::float::FloatCore; -use crate::{ - util::{cast_nom_err, write_into_vec_left_padded}, - *, -}; - -type DecodeIn<'input> = BSlice<'input, u8, Msb0>; +#[allow(clippy::wildcard_imports)] +use crate::{util::cast_nom_err, *}; /// Returns the value of a decoding attempt #[derive(Debug, PartialEq)] @@ -62,13 +54,12 @@ pub struct Decoded { /// result, /// Decoded { /// bytes_consumed: 4, -/// decoded: en302636_4_1::BasicHeader { -/// version: 1, -/// next_header: en302636_4_1::NextAfterBasic::SecuredPacket, -/// reserved: bits!(0;8), -/// lifetime: en302636_4_1::Lifetime(21), -/// remaining_hop_limit: 1 -/// } +/// decoded: en302636_4_1::BasicHeader::try_new( +/// 1, +/// en302636_4_1::NextAfterBasic::SecuredPacket, +/// en302636_4_1::Lifetime(21), +/// 1 +/// ).expect("Failed to create BasicHeader") /// } /// ); /// ``` @@ -129,9 +120,9 @@ impl UnsecuredHeader { #[cfg(feature = "json")] /// Tries to deserialize an unsecured GeoNetworking header from JSON. /// ### Usage - /// ``` + /// ```rust /// # use geonetworking::*; - /// let json_header = r#"{"basic":{"version":1,"next_header":"CommonHeader","reserved":[false,false,false,false,false,false,false,false],"lifetime":80,"remaining_hop_limit":1},"secured":null,"common":{"next_header":"BTPB","reserved_1":[false,false,false,false],"header_type_and_subtype":{"TopologicallyScopedBroadcast":"SingleHop"},"traffic_class":{"store_carry_forward":false,"channel_offload":false,"traffic_class_id":2},"flags":[false,false,false,false,false,false,false,false],"payload_length":8,"maximum_hop_limit":1,"reserved_2":[false,false,false,false,false,false,false,false]},"extended":{"SHB":{"source_position_vector":{"gn_address":{"manually_configured":false,"station_type":"Unknown","reserved":[false,true,false,false,false,false,false,true,true,false],"address":[0,96,224,105,87,141]},"timestamp":542947520,"latitude":535574568,"longitude":99765648,"position_accuracy":false,"speed":680,"heading":2122},"media_dependent_data":[127,0,184,0]}}}"#; + /// let json_header = r#"{"basic":{"version":1,"next_header":"CommonHeader","reserved":0,"lifetime":80,"remaining_hop_limit":1},"secured":null,"common":{"next_header":"BTPB","reserved_1":0,"header_type_and_subtype":{"TopologicallyScopedBroadcast":"SingleHop"},"traffic_class":{"store_carry_forward":false,"channel_offload":false,"traffic_class_id":2},"flags":[false,false,false,false,false,false,false,false],"payload_length":8,"maximum_hop_limit":1,"reserved_2":0},"extended":{"SHB":{"source_position_vector":{"gn_address":{"manually_configured":false,"station_type":"Unknown","reserved":262,"address":[0,96,224,105,87,141]},"timestamp":542947520,"latitude":535574568,"longitude":99765648,"position_accuracy":false,"speed":680,"heading":2122},"media_dependent_data":[127,0,184,0]}}}"#; /// let payload: &'static [u8] = &[0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03]; /// let unsecured_header = UnsecuredHeader::from_json(json_header).unwrap(); /// let unsecured_packet: Packet = unsecured_header.with_payload(payload).expect("REASON"); @@ -190,22 +181,13 @@ impl From>> for DecodeError { } } -impl From>> for DecodeError<&'_ [u8]> { - fn from(value: DecodeError>) -> Self { - match value { - DecodeError::IntegerError(s) => Self::IntegerError(s), - DecodeError::EnumError(s) => Self::EnumError(s), - DecodeError::StringError(s) => Self::StringError(s), - DecodeError::ArrayError(s) => Self::ArrayError(s), - DecodeError::ParserError(s) => Self::ParserError(s), - DecodeError::Nom(_, k) => Self::Nom(&[], k), - #[cfg(feature = "json")] - DecodeError::Json(s) => Self::Json(s), - } +impl ErrorConvert> for nom::error::Error<(&[u8], usize)> { + fn convert(self) -> DecodeError<&'static [u8]> { + DecodeError::Nom(&[], self.code) } } -impl From> for DecodeError> { +impl From> for DecodeError<(&'_ [u8], usize)> { fn from(value: DecodeError<&'_ [u8]>) -> Self { match value { DecodeError::IntegerError(s) => Self::IntegerError(s), @@ -213,7 +195,7 @@ impl From> for DecodeError> { DecodeError::StringError(s) => Self::StringError(s), DecodeError::ArrayError(s) => Self::ArrayError(s), DecodeError::ParserError(s) => Self::ParserError(s), - DecodeError::Nom(_, k) => Self::Nom([0u8].bitwise(), k), + DecodeError::Nom(_, k) => Self::Nom((&[], 0), k), #[cfg(feature = "json")] DecodeError::Json(s) => Self::Json(s), } @@ -238,221 +220,109 @@ impl FromExternalError for DecodeError { pub type IResult = nom::IResult>; -pub(crate) trait BitwiseDecodable { - /// Trait implemented by binary input data formats - /// that can be decoded using the `Decode` trait - fn bitwise(&self) -> DecodeIn<'_>; -} - -macro_rules! impl_decodable { - ($typ:ty) => { - impl BitwiseDecodable for $typ { - fn bitwise(&self) -> DecodeIn<'_> { - DecodeIn::from(BitSlice::::from_slice(self)) - } - } - }; -} - -impl_decodable![alloc::vec::Vec]; -impl_decodable![Bytes]; -impl_decodable![&[u8]]; - -impl BitwiseDecodable for [u8; SIZE] { - fn bitwise(&self) -> DecodeIn<'_> { - DecodeIn::from(BitSlice::::from_slice(self)) - } -} - -impl BitwiseDecodable for BitVec { - fn bitwise(&self) -> DecodeIn<'_> { - DecodeIn::from(self.as_bitslice()) - } -} trait InternalDecode<'s> { - fn decode_bitwise(_: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - unimplemented!("This type does not support bitwise decoding!") - } - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized; } -impl<'s> InternalDecode<'s> for i32 { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - map_res(take(32usize), |bits: DecodeIn<'_>| { - let mut vec = vec![]; - write_into_vec_left_padded(bits, &mut vec); - vec.try_into().map(i32::from_be_bytes).map_err(|_| { - DecodeError::IntegerError::( - "Integer value does not fit into 32 bits!".into(), - ) - }) - })(input) - } +macro_rules! decode_integer { + ($typ:ty, $size:literal) => { + impl<'s> InternalDecode<'s> for $typ { + fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> + where + Self: Sized, + { + let (input, bytes) = take($size)(input)?; - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> - where - Self: Sized, - { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; - Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, - )) - } + let value = <$typ>::from_be_bytes(bytes.try_into().expect(concat!( + "took", + $size, + "bytes, but result has different size" + ))); + + Ok((input, value)) + } + } + }; } -impl<'s> InternalDecode<'s> for bool { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - map(take(1u8), |bits: DecodeIn<'_>| bits[0])(input) - } +decode_integer!(i16, 2usize); +decode_integer!(u16, 2usize); +decode_integer!(u32, 4usize); +decode_integer!(i32, 4usize); +impl<'s, const SIZE: usize> InternalDecode<'s> for [u8; SIZE] { fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; - Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, - )) - } -} - -fn read_as_uint<'input, I: Integer + FromPrimitive>( - bit_count: usize, -) -> impl FnMut(DecodeIn<'input>) -> IResult, I> { - map_res(take(bit_count), |bits: DecodeIn<'_>| { - #[allow( - clippy::cast_possible_truncation, - clippy::cast_sign_loss, - clippy::cast_precision_loss - )] - let padding_bytes = 16 - ((bits.len() as f64 / 8.).ceil() as usize); - let mut vec = alloc::vec![0u8; padding_bytes]; + let mut output = [0u8; SIZE]; - write_into_vec_left_padded(bits, &mut vec); - - match vec.try_into() { - Ok(arr) => I::from_i128(i128::from_be_bytes(arr)).ok_or_else(|| { - DecodeError::IntegerError::(alloc::format!( - "Integer value does not fit into {} bits!", - bits.len() - )) - }), - Err(_) => Err(DecodeError::IntegerError( - "Error fitting bit slice into 16 bytes!".into(), - )), - } - }) -} - -fn read_speed_value(input: DecodeIn<'_>) -> IResult, i16> { - map_res(take(15usize), |bits: DecodeIn<'_>| { - let mut bitvec = bits.to_bitvec(); - if bitvec[0] { - bitvec.insert(1, false); + let mut input = input; + for item in &mut output { + (input, *item) = take(1usize)(input).map(|(rem, bytes)| (rem, bytes[0]))?; } - let mut vec = alloc::vec![]; - - write_into_vec_left_padded(bitvec.bitwise(), &mut vec); - - vec.try_into().map(i16::from_be_bytes).map_err(|_| { - DecodeError::IntegerError::( - "Integer value does not fit into 16 signed bits!".into(), - ) - }) - })(input) -} -impl<'s, const SIZE: usize> InternalDecode<'s> for Bits { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - map(take(SIZE), |bits: DecodeIn<'_>| Bits(bits.to_bitvec()))(input) + Ok((input, output)) } +} +impl<'s, const SIZE: usize> InternalDecode<'s> for [bool; SIZE] { + /// Note: The remaining input stream won't contain not consumed bits (behavior of `nom::bits`). + /// All remaining bits of a "started" byte will be lost! + /// + /// It's recommended to only use this with `SIZE` in multiples of 8. fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; - Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, - )) - } -} + nom::bits::bits::<_, _, nom::error::Error<(&[u8], usize)>, _, _>(|data| { + let mut output = [false; SIZE]; -impl<'s, const SIZE: usize> InternalDecode<'s> for [u8; SIZE] { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - map_res(take(SIZE * 8), |bits: DecodeIn<'_>| { - bits.chunks(8) - .map(bitvec::field::BitField::load_be::) - .collect::>() - .try_into() - .map_err(|_| { - DecodeError::ArrayError::(alloc::format!( - "Failed to fit bits into byte vec of size {SIZE}" - )) - }) - })(input) - } + let mut data = data; + for item in &mut output { + (data, *item) = nom::bits::streaming::bool(data)?; + } - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> - where - Self: Sized, - { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; - Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, - )) + Ok((data, output)) + })(input) } } impl<'s> InternalDecode<'s> for en302636_4_1::Address { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - into(tuple(( - bool::decode_bitwise, - en302636_4_1::StationType::decode_bitwise, - Bits::<10>::decode_bitwise, - <[u8; 6]>::decode_bitwise, - )))(input) - } - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; + let (input, bytes) = take(1usize)(input)?; + let manually_configured = (bytes[0] & 0x80) > 1; // first bit + + let station_type_int = (bytes[0] & 0x7c) >> 2; // next 5 bits + let station_type = en302636_4_1::StationType::try_from(station_type_int) + .map_err(|err| nom::Err::Error(DecodeError::EnumError(err)))?; + + let msb_part = bytes[0] & 0x03; // remaining 2 bits + let (input, bytes) = take(1usize)(input)?; + let reserved_u16 = (u16::from(msb_part) << 8) | u16::from(bytes[0]); + let reserved = u10::from_u16(reserved_u16); + + let (input, address) = <[u8; 6]>::decode_bytewise(input)?; + Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, + input, + Self { + manually_configured, + station_type, + reserved, + address, + }, )) } } -impl From<(bool, en302636_4_1::StationType, Bits<10>, [u8; 6])> for en302636_4_1::Address { - fn from(value: (bool, en302636_4_1::StationType, Bits<10>, [u8; 6])) -> Self { +impl From<(bool, en302636_4_1::StationType, u10, [u8; 6])> for en302636_4_1::Address { + fn from(value: (bool, en302636_4_1::StationType, u10, [u8; 6])) -> Self { Self { manually_configured: value.0, station_type: value.1, @@ -462,188 +332,78 @@ impl From<(bool, en302636_4_1::StationType, Bits<10>, [u8; 6])> for en302636_4_1 } } -impl<'s> InternalDecode<'s> for en302636_4_1::StationType { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - map_res(read_as_uint::(5), |val| match val { - 0 => Ok::>(Self::Unknown), - 1 => Ok(Self::Pedestrian), - 2 => Ok(Self::Cyclist), - 3 => Ok(Self::Moped), - 4 => Ok(Self::Motorcycle), - 5 => Ok(Self::PassengerCar), - 6 => Ok(Self::Bus), - 7 => Ok(Self::LightTruck), - 8 => Ok(Self::HeavyTruck), - 9 => Ok(Self::Trailer), - 10 => Ok(Self::SpecialVehicle), - 11 => Ok(Self::Tram), - 15 => Ok(Self::RoadSideUnit), - i => Err(DecodeError::EnumError(alloc::format!( - "No corresponding station type for value {i}!" - ))), - })(input) - } - - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> - where - Self: Sized, - { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; - Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, - )) - } -} - impl<'s> InternalDecode<'s> for en302636_4_1::BasicHeader { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - into(tuple(( - read_as_uint(4), - en302636_4_1::NextAfterBasic::decode_bitwise, - Bits::<8>::decode_bitwise, - en302636_4_1::Lifetime::decode_bitwise, - read_as_uint(8), - )))(input) - } - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; - Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, - )) - } -} + let (input, bytes) = take(1usize)(input)?; + let byte = bytes[0]; + let version = u4::from_u8((byte >> 4) & 0x0F); + let next_header = en302636_4_1::NextAfterBasic::try_from(byte & 0x0F) + .map_err(|err| nom::Err::Error(DecodeError::EnumError(err)))?; -impl - From<( - u8, - en302636_4_1::NextAfterBasic, - Bits<8>, - en302636_4_1::Lifetime, - u8, - )> for en302636_4_1::BasicHeader -{ - fn from( - value: ( - u8, - en302636_4_1::NextAfterBasic, - Bits<8>, - en302636_4_1::Lifetime, - u8, - ), - ) -> Self { - Self { - version: value.0, - next_header: value.1, - reserved: value.2, - lifetime: value.3, - remaining_hop_limit: value.4, - } - } -} + let (input, bytes) = take(1usize)(input)?; + let reserved = bytes[0]; -impl<'s> InternalDecode<'s> for en302636_4_1::NextAfterBasic { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - map_res(read_as_uint::(4), |val| match val { - 0 => Ok::>(Self::Any), - 1 => Ok(Self::CommonHeader), - 2 => Ok(Self::SecuredPacket), - i => Err(DecodeError::EnumError(alloc::format!( - "No corresponding header type for value {i}!" - ))), - })(input) - } + let (input, bytes) = take(1usize)(input)?; + let lifetime = en302636_4_1::Lifetime::from_raw(bytes[0]); - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> - where - Self: Sized, - { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; - Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, - )) - } -} + let (input, bytes) = take(1usize)(input)?; + let remaining_hop_limit = bytes[0]; -impl<'s> InternalDecode<'s> for en302636_4_1::Lifetime { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - map(read_as_uint::(8), Self)(input) - } - - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> - where - Self: Sized, - { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, + input, + Self { + version, + next_header, + reserved, + lifetime, + remaining_hop_limit, + }, )) } } impl<'s> InternalDecode<'s> for en302636_4_1::Timestamp { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - map(read_as_uint::(32), Self)(input) - } - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; - Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, - )) + let (input, value) = u32::decode_bytewise(input)?; + + Ok((input, Self(value))) } } impl<'s> InternalDecode<'s> for en302636_4_1::LongPositionVector { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - into(tuple(( - en302636_4_1::Address::decode_bitwise, - en302636_4_1::Timestamp::decode_bitwise, - i32::decode_bitwise, - i32::decode_bitwise, - bool::decode_bitwise, - read_speed_value, - read_as_uint(16), - )))(input) - } - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; + let (input, gn_address) = en302636_4_1::Address::decode_bytewise(input)?; + let (input, timestamp) = en302636_4_1::Timestamp::decode_bytewise(input)?; + let (input, latitude) = i32::decode_bytewise(input)?; + let (input, longitude) = i32::decode_bytewise(input)?; + + let (input, bytes) = take(2usize)(input)?; + let position_accuracy = (bytes[0] & 0x80) > 0; + let speed_i16 = (i16::from(bytes[0]) << 8) | i16::from(bytes[1]); + let speed = i15::from_i16(speed_i16 & 0x7FFF); + + let (input, heading) = u16::decode_bytewise(input)?; + Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, + input, + Self { + gn_address, + timestamp, + latitude, + longitude, + position_accuracy, + speed, + heading, + }, )) } } @@ -655,7 +415,7 @@ impl i32, i32, bool, - i16, + i15, u16, )> for en302636_4_1::LongPositionVector { @@ -666,7 +426,7 @@ impl i32, i32, bool, - i16, + i15, u16, ), ) -> Self { @@ -683,26 +443,23 @@ impl } impl<'s> InternalDecode<'s> for en302636_4_1::ShortPositionVector { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - into(tuple(( - en302636_4_1::Address::decode_bitwise, - en302636_4_1::Timestamp::decode_bitwise, - i32::decode_bitwise, - i32::decode_bitwise, - )))(input) - } - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; + let (input, gn_address) = en302636_4_1::Address::decode_bytewise(input)?; + let (input, timestamp) = en302636_4_1::Timestamp::decode_bytewise(input)?; + let (input, latitude) = i32::decode_bytewise(input)?; + let (input, longitude) = i32::decode_bytewise(input)?; + Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, + input, + Self { + gn_address, + timestamp, + latitude, + longitude, + }, )) } } @@ -721,31 +478,39 @@ impl From<(en302636_4_1::Address, en302636_4_1::Timestamp, i32, i32)> } impl<'s> InternalDecode<'s> for en302636_4_1::TrafficClass { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> + fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - into(tuple(( - bool::decode_bitwise, - bool::decode_bitwise, - read_as_uint(6), - )))(input) + nom::bits::bits::<_, _, nom::error::Error<(&[u8], usize)>, _, _>(|data| { + let (data, scf) = nom::bits::streaming::bool(data)?; + let (data, choff) = nom::bits::streaming::bool(data)?; + let (data, traffic_class_u8) = nom::bits::streaming::take(6usize)(data)?; + + Ok(( + data, + Self { + store_carry_forward: scf, + channel_offload: choff, + traffic_class_id: u6::from_u8(traffic_class_u8), + }, + )) + })(input) } +} - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> - where - Self: Sized, - { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; - Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, - )) +impl From<(u8, u8, u6)> for en302636_4_1::TrafficClass { + fn from(value: (u8, u8, u6)) -> Self { + Self { + store_carry_forward: value.0 > 0, + channel_offload: value.1 > 0, + traffic_class_id: value.2, + } } } -impl From<(bool, bool, u8)> for en302636_4_1::TrafficClass { - fn from(value: (bool, bool, u8)) -> Self { +impl From<(bool, bool, u6)> for en302636_4_1::TrafficClass { + fn from(value: (bool, bool, u6)) -> Self { Self { store_carry_forward: value.0, channel_offload: value.1, @@ -754,189 +519,76 @@ impl From<(bool, bool, u8)> for en302636_4_1::TrafficClass { } } -impl<'s> InternalDecode<'s> for en302636_4_1::NextAfterCommon { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - map_res(read_as_uint::(4), |val| match val { - 0 => Ok::>(Self::Any), - 1 => Ok(Self::BTPA), - 2 => Ok(Self::BTPB), - 3 => Ok(Self::IPv6), - i => Err(DecodeError::EnumError(alloc::format!( - "No corresponding header type for value {i}!" - ))), - })(input) - } - +impl<'s> InternalDecode<'s> for en302636_4_1::CommonHeader { fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; - Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, - )) - } -} + let (input, bytes) = take(1usize)(input)?; + let byte = bytes[0]; + let next_header = en302636_4_1::NextAfterCommon::try_from((byte >> 4) & 0x0F) + .map_err(|err| nom::Err::Error(DecodeError::EnumError(err)))?; + let reserved_1 = u4::from_u8(byte & 0x0F); -impl<'s> InternalDecode<'s> for en302636_4_1::HeaderType { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - map_res( - pair(read_as_uint(4), read_as_uint(4)), - |(ty, subtype): (u8, u8)| { - let error = DecodeError::EnumError::(alloc::format!( - "No corresponding header type for value {ty} and subtype value {subtype}!" - )); - match ty { - 0 => Ok::>(Self::Any), - 1 => Ok(Self::Beacon), - 2 => Ok(Self::GeoUnicast), - 3 => match subtype { - 0 => Ok(Self::GeoAnycast(en302636_4_1::AreaType::Circular)), - 1 => Ok(Self::GeoAnycast(en302636_4_1::AreaType::Rectangular)), - 2 => Ok(Self::GeoAnycast(en302636_4_1::AreaType::Ellipsoidal)), - _ => Err(error), - }, - 4 => match subtype { - 0 => Ok(Self::GeoBroadcast(en302636_4_1::AreaType::Circular)), - 1 => Ok(Self::GeoBroadcast(en302636_4_1::AreaType::Rectangular)), - 2 => Ok(Self::GeoBroadcast(en302636_4_1::AreaType::Ellipsoidal)), - _ => Err(error), - }, - 5 => match subtype { - 0 => Ok(Self::TopologicallyScopedBroadcast( - en302636_4_1::BroadcastType::SingleHop, - )), - 1 => Ok(Self::TopologicallyScopedBroadcast( - en302636_4_1::BroadcastType::MultiHop, - )), - _ => Err(error), - }, - 6 => match subtype { - 0 => Ok(Self::LocationService( - en302636_4_1::LocationServiceType::Request, - )), - 1 => Ok(Self::LocationService( - en302636_4_1::LocationServiceType::Reply, - )), - _ => Err(error), - }, - _ => Err(error), - } - }, - )(input) - } + let (input, bytes) = take(1usize)(input)?; + let header_type_and_subtype = en302636_4_1::HeaderType::try_from(bytes[0]) + .map_err(|err| nom::Err::Error(DecodeError::EnumError(err)))?; - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> - where - Self: Sized, - { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; - Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, - )) - } -} + let (input, traffic_class) = en302636_4_1::TrafficClass::decode_bytewise(input)?; + let (input, flags) = <[bool; 8]>::decode_bytewise(input)?; + let (input, payload_length) = u16::decode_bytewise(input)?; -impl<'s> InternalDecode<'s> for en302636_4_1::CommonHeader { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - into(tuple(( - en302636_4_1::NextAfterCommon::decode_bitwise, - Bits::<4>::decode_bitwise, - en302636_4_1::HeaderType::decode_bitwise, - en302636_4_1::TrafficClass::decode_bitwise, - Bits::<8>::decode_bitwise, - read_as_uint(16), - read_as_uint(8), - Bits::<8>::decode_bitwise, - )))(input) - } + let (input, bytes) = take(1usize)(input)?; + let maximum_hop_limit = bytes[0]; + + let (input, bytes) = take(1usize)(input)?; + let reserved_2 = bytes[0]; - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> - where - Self: Sized, - { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, + input, + Self { + next_header, + reserved_1, + header_type_and_subtype, + traffic_class, + flags, + payload_length, + maximum_hop_limit, + reserved_2, + }, )) } } -impl - From<( - en302636_4_1::NextAfterCommon, - Bits<4>, - en302636_4_1::HeaderType, - en302636_4_1::TrafficClass, - Bits<8>, - u16, - u8, - Bits<8>, - )> for en302636_4_1::CommonHeader -{ - fn from( - value: ( - en302636_4_1::NextAfterCommon, - Bits<4>, - en302636_4_1::HeaderType, - en302636_4_1::TrafficClass, - Bits<8>, - u16, - u8, - Bits<8>, - ), - ) -> Self { - Self { - next_header: value.0, - reserved_1: value.1, - header_type_and_subtype: value.2, - traffic_class: value.3, - flags: value.4, - payload_length: value.5, - maximum_hop_limit: value.6, - reserved_2: value.7, - } - } -} - impl<'s> InternalDecode<'s> for en302636_4_1::GeoAnycast { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - into(tuple(( - read_as_uint(16), - Bits::<16>::decode_bitwise, - en302636_4_1::LongPositionVector::decode_bitwise, - i32::decode_bitwise, - i32::decode_bitwise, - read_as_uint(16), - read_as_uint(16), - read_as_uint(16), - Bits::<16>::decode_bitwise, - )))(input) - } - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; + let (input, sequence_number) = u16::decode_bytewise(input)?; + let (input, reserved_1) = u16::decode_bytewise(input)?; + let (input, source_position_vector) = + en302636_4_1::LongPositionVector::decode_bytewise(input)?; + let (input, geo_area_position_latitude) = i32::decode_bytewise(input)?; + let (input, geo_area_position_longitude) = i32::decode_bytewise(input)?; + let (input, distance_a) = u16::decode_bytewise(input)?; + let (input, distance_b) = u16::decode_bytewise(input)?; + let (input, angle) = u16::decode_bytewise(input)?; + let (input, reserved_2) = u16::decode_bytewise(input)?; + Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, + input, + Self { + sequence_number, + reserved_1, + source_position_vector, + geo_area_position_latitude, + geo_area_position_longitude, + distance_a, + distance_b, + angle, + reserved_2, + }, )) } } @@ -944,27 +596,27 @@ impl<'s> InternalDecode<'s> for en302636_4_1::GeoAnycast { impl From<( u16, - Bits<16>, + u16, en302636_4_1::LongPositionVector, i32, i32, u16, u16, u16, - Bits<16>, + u16, )> for en302636_4_1::GeoAnycast { fn from( value: ( u16, - Bits<16>, + u16, en302636_4_1::LongPositionVector, i32, i32, u16, u16, u16, - Bits<16>, + u16, ), ) -> Self { Self { @@ -982,26 +634,25 @@ impl } impl<'s> InternalDecode<'s> for en302636_4_1::GeoUnicast { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - into(tuple(( - read_as_uint(16), - Bits::<16>::decode_bitwise, - en302636_4_1::LongPositionVector::decode_bitwise, - en302636_4_1::ShortPositionVector::decode_bitwise, - )))(input) - } - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; + let (input, sequence_number) = u16::decode_bytewise(input)?; + let (input, reserved) = u16::decode_bytewise(input)?; + let (input, source_position_vector) = + en302636_4_1::LongPositionVector::decode_bytewise(input)?; + let (input, destination_position_vector) = + en302636_4_1::ShortPositionVector::decode_bytewise(input)?; + Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, + input, + Self { + sequence_number, + reserved, + source_position_vector, + destination_position_vector, + }, )) } } @@ -1009,7 +660,7 @@ impl<'s> InternalDecode<'s> for en302636_4_1::GeoUnicast { impl From<( u16, - Bits<16>, + u16, en302636_4_1::LongPositionVector, en302636_4_1::ShortPositionVector, )> for en302636_4_1::GeoUnicast @@ -1017,7 +668,7 @@ impl fn from( value: ( u16, - Bits<16>, + u16, en302636_4_1::LongPositionVector, en302636_4_1::ShortPositionVector, ), @@ -1032,33 +683,30 @@ impl } impl<'s> InternalDecode<'s> for en302636_4_1::TopologicallyScopedBroadcast { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - into(tuple(( - read_as_uint(16), - Bits::<16>::decode_bitwise, - en302636_4_1::LongPositionVector::decode_bitwise, - )))(input) - } - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; + let (input, sequence_number) = u16::decode_bytewise(input)?; + let (input, reserved) = u16::decode_bytewise(input)?; + let (input, source_position_vector) = + en302636_4_1::LongPositionVector::decode_bytewise(input)?; + Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, + input, + Self { + sequence_number, + reserved, + source_position_vector, + }, )) } } -impl From<(u16, Bits<16>, en302636_4_1::LongPositionVector)> +impl From<(u16, u16, en302636_4_1::LongPositionVector)> for en302636_4_1::TopologicallyScopedBroadcast { - fn from(value: (u16, Bits<16>, en302636_4_1::LongPositionVector)) -> Self { + fn from(value: (u16, u16, en302636_4_1::LongPositionVector)) -> Self { Self { sequence_number: value.0, reserved: value.1, @@ -1068,24 +716,20 @@ impl From<(u16, Bits<16>, en302636_4_1::LongPositionVector)> } impl<'s> InternalDecode<'s> for en302636_4_1::SingleHopBroadcast { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - into(tuple(( - en302636_4_1::LongPositionVector::decode_bitwise, - <[u8; 4]>::decode_bitwise, - )))(input) - } - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; + let (input, source_position_vector) = + en302636_4_1::LongPositionVector::decode_bytewise(input)?; + let (input, media_dependent_data) = <[u8; 4]>::decode_bytewise(input)?; + Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, + input, + Self { + source_position_vector, + media_dependent_data, + }, )) } } @@ -1100,21 +744,18 @@ impl From<(en302636_4_1::LongPositionVector, [u8; 4])> for en302636_4_1::SingleH } impl<'s> InternalDecode<'s> for en302636_4_1::Beacon { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - into(en302636_4_1::LongPositionVector::decode_bitwise)(input) - } - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; + let (input, source_position_vector) = + en302636_4_1::LongPositionVector::decode_bytewise(input)?; + Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, + input, + Self { + source_position_vector, + }, )) } } @@ -1128,26 +769,24 @@ impl From for en302636_4_1::Beacon { } impl<'s> InternalDecode<'s> for en302636_4_1::LSRequest { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - into(tuple(( - read_as_uint(16), - Bits::<16>::decode_bitwise, - en302636_4_1::LongPositionVector::decode_bitwise, - en302636_4_1::Address::decode_bitwise, - )))(input) - } - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; + let (input, sequence_number) = u16::decode_bytewise(input)?; + let (input, reserved) = u16::decode_bytewise(input)?; + let (input, source_position_vector) = + en302636_4_1::LongPositionVector::decode_bytewise(input)?; + let (input, request_gn_address) = en302636_4_1::Address::decode_bytewise(input)?; + Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, + input, + Self { + sequence_number, + reserved, + source_position_vector, + request_gn_address, + }, )) } } @@ -1155,7 +794,7 @@ impl<'s> InternalDecode<'s> for en302636_4_1::LSRequest { impl From<( u16, - Bits<16>, + u16, en302636_4_1::LongPositionVector, en302636_4_1::Address, )> for en302636_4_1::LSRequest @@ -1163,7 +802,7 @@ impl fn from( value: ( u16, - Bits<16>, + u16, en302636_4_1::LongPositionVector, en302636_4_1::Address, ), @@ -1178,26 +817,25 @@ impl } impl<'s> InternalDecode<'s> for en302636_4_1::LSReply { - fn decode_bitwise(input: DecodeIn<'_>) -> IResult, Self> - where - Self: Sized, - { - into(tuple(( - read_as_uint(16), - Bits::<16>::decode_bitwise, - en302636_4_1::LongPositionVector::decode_bitwise, - en302636_4_1::ShortPositionVector::decode_bitwise, - )))(input) - } - fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (remaining, instance) = Self::decode_bitwise(input.bitwise()).map_err(cast_nom_err)?; + let (input, sequence_number) = u16::decode_bytewise(input)?; + let (input, reserved) = u16::decode_bytewise(input)?; + let (input, source_position_vector) = + en302636_4_1::LongPositionVector::decode_bytewise(input)?; + let (input, destination_position_vector) = + en302636_4_1::ShortPositionVector::decode_bytewise(input)?; + Ok(( - &input[(input.len() - Integer::div_ceil(&remaining.len(), &8usize))..], - instance, + input, + Self { + sequence_number, + reserved, + source_position_vector, + destination_position_vector, + }, )) } } @@ -1205,7 +843,7 @@ impl<'s> InternalDecode<'s> for en302636_4_1::LSReply { impl From<( u16, - Bits<16>, + u16, en302636_4_1::LongPositionVector, en302636_4_1::ShortPositionVector, )> for en302636_4_1::LSReply @@ -1213,7 +851,7 @@ impl fn from( value: ( u16, - Bits<16>, + u16, en302636_4_1::LongPositionVector, en302636_4_1::ShortPositionVector, ), @@ -1229,53 +867,53 @@ impl fn wrap_in_some<'input, T, F>( parser: F, -) -> impl FnMut(DecodeIn<'input>) -> IResult, Option> +) -> impl FnMut(&'input [u8]) -> IResult<&'input [u8], Option> where - F: FnMut(DecodeIn<'input>) -> IResult, T>, + F: FnMut(&'input [u8]) -> IResult<&'input [u8], T>, { map(parser, |res| Some(res)) } fn read_extended( header_type_and_subclass: en302636_4_1::HeaderType, - input: DecodeIn<'_>, -) -> IResult, Option> { + input: &'_ [u8], +) -> IResult<&'_ [u8], Option> { match header_type_and_subclass { en302636_4_1::HeaderType::Any => Ok((input, None)), en302636_4_1::HeaderType::Beacon => wrap_in_some(map( - en302636_4_1::Beacon::decode_bitwise, + en302636_4_1::Beacon::decode_bytewise, en302636_4_1::ExtendedHeader::Beacon, ))(input), en302636_4_1::HeaderType::GeoUnicast => wrap_in_some(map( - en302636_4_1::GeoUnicast::decode_bitwise, + en302636_4_1::GeoUnicast::decode_bytewise, en302636_4_1::ExtendedHeader::GUC, ))(input), en302636_4_1::HeaderType::GeoAnycast(_) => wrap_in_some(map( - en302636_4_1::GeoAnycast::decode_bitwise, + en302636_4_1::GeoAnycast::decode_bytewise, en302636_4_1::ExtendedHeader::GAC, ))(input), en302636_4_1::HeaderType::GeoBroadcast(_) => wrap_in_some(map( - en302636_4_1::GeoAnycast::decode_bitwise, + en302636_4_1::GeoAnycast::decode_bytewise, en302636_4_1::ExtendedHeader::GBC, ))(input), en302636_4_1::HeaderType::TopologicallyScopedBroadcast( en302636_4_1::BroadcastType::SingleHop, ) => wrap_in_some(map( - en302636_4_1::SingleHopBroadcast::decode_bitwise, + en302636_4_1::SingleHopBroadcast::decode_bytewise, en302636_4_1::ExtendedHeader::SHB, ))(input), en302636_4_1::HeaderType::TopologicallyScopedBroadcast(_) => wrap_in_some(map( - en302636_4_1::TopologicallyScopedBroadcast::decode_bitwise, + en302636_4_1::TopologicallyScopedBroadcast::decode_bytewise, en302636_4_1::ExtendedHeader::TSB, ))(input), en302636_4_1::HeaderType::LocationService(en302636_4_1::LocationServiceType::Request) => { wrap_in_some(map( - en302636_4_1::LSRequest::decode_bitwise, + en302636_4_1::LSRequest::decode_bytewise, en302636_4_1::ExtendedHeader::LSRequest, ))(input) } en302636_4_1::HeaderType::LocationService(_) => wrap_in_some(map( - en302636_4_1::LSReply::decode_bitwise, + en302636_4_1::LSReply::decode_bytewise, en302636_4_1::ExtendedHeader::LSReply, ))(input), } @@ -1295,8 +933,7 @@ impl<'s> InternalDecode<'s> for Packet<'s> { )) })?; let (input, common) = - en302636_4_1::CommonHeader::decode_bitwise(data_payload.bitwise()) - .map_err(cast_nom_err)?; + en302636_4_1::CommonHeader::decode_bytewise(data_payload).map_err(cast_nom_err)?; let (_, extended) = read_extended(common.header_type_and_subtype, input).map_err(cast_nom_err)?; Ok(( @@ -1309,18 +946,12 @@ impl<'s> InternalDecode<'s> for Packet<'s> { }, )) } else { - let bitwise = input.bitwise(); let (remaining, common) = - en302636_4_1::CommonHeader::decode_bitwise(bitwise).map_err(cast_nom_err)?; + en302636_4_1::CommonHeader::decode_bytewise(input).map_err(cast_nom_err)?; let (remaining, extended) = read_extended(common.header_type_and_subtype, remaining).map_err(cast_nom_err)?; - if (bitwise.len() - remaining.len()) % 8 != 0 { - return Err(nom::Err::Error(DecodeError::ParserError( - "Bit Error: Unexpected unalignment!".into(), - ))); - } - let input = &input[((bitwise.len() - remaining.len()) / 8)..]; - let (input, payload) = take(common.payload_length)(input)?; + + let (input, payload) = take(common.payload_length)(remaining)?; Ok(( input, Self::Unsecured { @@ -1335,7 +966,7 @@ impl<'s> InternalDecode<'s> for Packet<'s> { } // ===================================================== -// Ieee1609Dot2 +// ETSI TS 103 097/ IEEE 1609.2 // ===================================================== struct Slice<'i>(&'i [u8]); @@ -1457,16 +1088,67 @@ fn decode_bytewise_enumerated>(input: &[u8]) -> IResult<&[u8], } } +/// Extracts bits from ASN.1 buffer +/// +/// First bit is the MSB of the first byte in ASN.1 +fn bitslice_to_bitvec(buffer: &[u8], offset: usize, count: usize) -> Vec { + let mut bitvec = vec![]; + + // iterate using 0-based index + for i in offset..(offset + count) { + let byte_idx = Integer::div_floor(&i, &8); + let bit_idx = (8 - (i % 8)) - 1; + + bitvec.push((buffer[byte_idx] >> bit_idx & 0x01) > 0); + } + + bitvec +} + +/// Decodes ASN.1 SEQUENCE preamble +/// +/// Note: Only execute, if there is either an extension bit or optional values present! +/// (Otherwise the sequence preamble will be omitted.) +fn decode_bytewise_sequence_preamble( + has_extension: bool, + presence_bits: usize, + input: &[u8], +) -> IResult<&[u8], (bool, Vec)> { + let (input, preamble) = take(util::bitstring_buffer_size(presence_bits))(input)?; + + let (ext, bitmap) = if has_extension { + let extension = (preamble[0] & 0b1000_0000) > 0; + let bitstring = bitslice_to_bitvec(preamble, 1, presence_bits); + + (extension, bitstring) + } else { + let bitstring = bitslice_to_bitvec(preamble, 0, presence_bits); + + (false, bitstring) + }; + + Ok((input, (ext, bitmap))) +} + +// ASN.1 OER "bitstring" values +// ASN.1 OER "extension addition presence bitmap", if used without constraints or as extensible fn decode_bytewise_bitstring( min: Option, max: Option, extensible: bool, input: &[u8], -) -> IResult<&[u8], BitVec> { +) -> IResult<&[u8], Vec> { match (min, max, extensible) { (Some(min), Some(max), false) if min == max => { - let (input, bytes) = take(Integer::div_ceil(&max, &8usize))(input)?; - let mut bitstring = bytes.view_bits::().to_bitvec(); + let (input, bytes) = take(util::bitstring_buffer_size(max))(input)?; + + let mut bitstring = vec![]; + for byte in bytes { + for i in (0..8).rev() { + bitstring.push((byte >> i & 0x01) > 0); + } + } + let to_pop = 8 - max % 8; if to_pop != 8 { (0..to_pop).for_each(|_| { @@ -1476,21 +1158,47 @@ fn decode_bytewise_bitstring( Ok((input, bitstring)) } _ => { + // length includes second (unused_bits) byte and subsequent bytes let (input, length) = decode_bytewise_length(input)?; - let (input, unused_octets) = + + // Note: using integer encoding is not 100% correct, but leads to same result in this case + let (input, unused_bits) = decode_bytewise_integer::(Some(0), Some(8), false, input)?; + if unused_bits > 7 { + return Err(nom::Err::Error(DecodeError::ParserError( + alloc::format!("Extension addition presence bitmap contains invalid unused bits indication: {unused_bits}"), + ))); + } + let (input, bytes) = take(length - 1)(input)?; - let mut bitstring = bytes.view_bits::().to_bitvec(); - if unused_octets != 8 { - (0..unused_octets).for_each(|_| { - bitstring.pop(); - }); + + let mut bitstring = vec![]; + for byte in bytes { + for i in (0..8).rev() { + bitstring.push((byte >> i & 0x01) > 0); + } } + + // remove padding bits + (0..unused_bits).for_each(|_| { + bitstring.pop(); + }); + Ok((input, bitstring)) } } } +impl<'s, const SIZE: usize> InternalDecode<'s> for ieee1609dot2::BitString { + fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> + where + Self: Sized, + { + let (rem, bitvec) = decode_bytewise_bitstring(Some(SIZE), Some(SIZE), false, input)?; + Ok((rem, Self::from(bitvec))) + } +} + fn decode_bytewise_octetstring( min: Option, max: Option, @@ -1508,12 +1216,6 @@ fn decode_bytewise_octetstring( } } -fn decode_bytewise_is_extended(input: &[u8]) -> IResult<&[u8], bool> { - map(peek(take(1usize)), |byte: &[u8]| { - byte[0] & 0b1000_0000 != 0b0000_0000 - })(input) -} - fn decode_bytewise_tag(input: &[u8]) -> IResult<&[u8], u64> { let (input, byte) = take(1usize)(input)?; match byte[0] & 0b0011_1111 { @@ -2202,7 +1904,8 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::PsidSsp<'s> { where Self: Sized, { - let (input, bitmap) = decode_bytewise_bitstring(Some(1), Some(1), false, input)?; + let (input, (_, bitmap)) = decode_bytewise_sequence_preamble(false, 1, input)?; + let (input, psid) = ieee1609dot2::Psid::decode_bytewise(input)?; let (input, ssp) = if bitmap[0] { map( @@ -2244,7 +1947,8 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::PsidSspRange<'s> { where Self: Sized, { - let (input, bitmap) = decode_bytewise_bitstring(Some(1), Some(1), false, input)?; + let (input, (_, bitmap)) = decode_bytewise_sequence_preamble(false, 1, input)?; + let (input, psid) = ieee1609dot2::Psid::decode_bytewise(input)?; let (input, ssp_range) = if bitmap[0] { map(ieee1609dot2::SspRange::decode_bytewise, Some)(input)? @@ -2544,25 +2248,29 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::SignedDataPayload<'s> { where Self: Sized, { - let (input, extended) = decode_bytewise_is_extended(input)?; - let (input, bitmap) = decode_bytewise_bitstring(Some(3), Some(3), false, input)?; - let (input, data) = if bitmap[1] { + let (input, (extended, bitmap)) = decode_bytewise_sequence_preamble(true, 2, input)?; + + let (input, data) = if bitmap[0] { map(ieee1609dot2::Ieee1609Dot2Data::decode_bytewise, Some)(input)? } else { (input, None) }; - let (input, ext_data_hash) = if bitmap[2] { + let (input, ext_data_hash) = if bitmap[1] { map(ieee1609dot2::HashedData::decode_bytewise, Some)(input)? } else { (input, None) }; let (input, omitted) = if extended { let (input, bitmap) = decode_bytewise_bitstring(Some(0), None, false, input)?; + + #[allow(clippy::get_first, reason = "similarity to subsequent lines")] let (mut input, omitted) = if bitmap.get(0).is_some_and(|bit| *bit) { decode_bytewise_open_type(|i| Ok((i, Some(()))), input)? } else { (input, None) }; + + // consume unknown extensions for bit in bitmap.get(1..).unwrap_or_default() { if *bit { input = decode_bytewise_octetstring(Some(0), None, false, input)?.0; @@ -2646,18 +2354,25 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::MissingCrlIdentifier<'s> { where Self: Sized, { - let (input, extended) = decode_bytewise_is_extended(input)?; + let (input, (extended, _)) = decode_bytewise_sequence_preamble(true, 0, input)?; + let (input, craca_id) = ieee1609dot2::HashedId3::decode_bytewise(input)?; - let (mut input, crl_series) = ieee1609dot2::CrlSeries::decode_bytewise(input)?; - if extended { - let (i, bitmap) = decode_bytewise_bitstring(Some(0), None, false, input)?; - input = i; - for bit in bitmap.get(1..).unwrap_or_default() { - if *bit { + let (input, crl_series) = ieee1609dot2::CrlSeries::decode_bytewise(input)?; + let input = if extended { + let (mut input, bitmap) = decode_bytewise_bitstring(Some(0), None, false, input)?; + + // consume unknown extensions + for bit in bitmap { + if bit { input = decode_bytewise_octetstring(Some(0), None, false, input)?.0; } } - } + + input + } else { + input + }; + Ok(( input, Self { @@ -2673,35 +2388,35 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::HeaderInfo<'s> { where Self: Sized, { - let (input, extended) = decode_bytewise_is_extended(input)?; - let (input, bitmap) = decode_bytewise_bitstring(Some(7), Some(7), false, input)?; + let (input, (extended, bitmap)) = decode_bytewise_sequence_preamble(true, 6, input)?; + let (input, psid) = ieee1609dot2::Psid::decode_bytewise(input)?; - let (input, generation_time) = if bitmap[1] { + let (input, generation_time) = if bitmap[0] { map(ieee1609dot2::Time64::decode_bytewise, Some)(input)? } else { (input, None) }; - let (input, expiry_time) = if bitmap[2] { + let (input, expiry_time) = if bitmap[1] { map(ieee1609dot2::Time64::decode_bytewise, Some)(input)? } else { (input, None) }; - let (input, generation_location) = if bitmap[3] { + let (input, generation_location) = if bitmap[2] { map(ieee1609dot2::ThreeDLocation::decode_bytewise, Some)(input)? } else { (input, None) }; - let (input, p2pcd_learning_request) = if bitmap[4] { + let (input, p2pcd_learning_request) = if bitmap[3] { map(ieee1609dot2::HashedId3::decode_bytewise, Some)(input)? } else { (input, None) }; - let (input, missing_crl_identifier) = if bitmap[5] { + let (input, missing_crl_identifier) = if bitmap[4] { map(ieee1609dot2::MissingCrlIdentifier::decode_bytewise, Some)(input)? } else { (input, None) }; - let (input, encryption_key) = if bitmap[6] { + let (input, encryption_key) = if bitmap[5] { map(ieee1609dot2::EncryptionKey::decode_bytewise, Some)(input)? } else { (input, None) @@ -2714,6 +2429,8 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::HeaderInfo<'s> { contributed_extensions, ) = if extended { let (input, bitmap) = decode_bytewise_bitstring(Some(0), None, false, input)?; + + #[allow(clippy::get_first, reason = "similarity to subsequent lines")] let (input, inline_p2pcd_request) = if bitmap.get(0).is_some_and(|bit| *bit) { decode_bytewise_open_type(ieee1609dot2::SequenceOfHashedId3::decode_bytewise, input) .map(|(rem, req)| (rem, Some(req)))? @@ -2741,11 +2458,14 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::HeaderInfo<'s> { } else { (input, None) }; + + // consume unknown extensions for bit in bitmap.get(4..).unwrap_or_default() { if *bit { input = decode_bytewise_octetstring(Some(0), None, false, input)?.0; } } + ( input, inline_p2pcd_request, @@ -2936,7 +2656,9 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::CertificateBase<'s> { { #[cfg(feature = "validate")] let (input_before, length_before) = (input, input.len()); - let (input, bitmap) = decode_bytewise_bitstring(Some(1), Some(1), false, input)?; + + let (input, (_, bitmap)) = decode_bytewise_sequence_preamble(false, 1, input)?; + let (input, version) = ieee1609dot2::Uint8::decode_bytewise(input)?; let (input, r_type) = ieee1609dot2::CertificateType::decode_bytewise(input)?; let (input, issuer) = ieee1609dot2::IssuerIdentifier::decode_bytewise(input)?; @@ -2949,11 +2671,11 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::CertificateBase<'s> { Ok(( input, Self { + version, r_type, - to_be_signed, issuer, + to_be_signed, signature, - version, #[cfg(feature = "validate")] raw: &input_before[..length_before - input.len()], }, @@ -2961,34 +2683,35 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::CertificateBase<'s> { } } +#[allow(clippy::too_many_lines)] impl<'s> InternalDecode<'s> for ieee1609dot2::ToBeSignedCertificate<'s> { #[allow(clippy::too_many_lines)] fn decode_bytewise<'input: 's>(input: &'input [u8]) -> IResult<&'input [u8], Self> where Self: Sized, { - let (input, extended) = decode_bytewise_is_extended(input)?; - let (input, bitmap) = decode_bytewise_bitstring(Some(8), Some(8), false, input)?; + let (input, (extended, bitmap)) = decode_bytewise_sequence_preamble(true, 7, input)?; + let (input, id) = ieee1609dot2::CertificateId::decode_bytewise(input)?; let (input, craca_id) = ieee1609dot2::HashedId3::decode_bytewise(input)?; let (input, crl_series) = ieee1609dot2::CrlSeries::decode_bytewise(input)?; let (input, validity_period) = ieee1609dot2::ValidityPeriod::decode_bytewise(input)?; - let (input, region) = if bitmap[1] { + let (input, region) = if bitmap[0] { map(ieee1609dot2::GeographicRegion::decode_bytewise, Some)(input)? } else { (input, None) }; - let (input, assurance_level) = if bitmap[2] { + let (input, assurance_level) = if bitmap[1] { map(ieee1609dot2::SubjectAssurance::decode_bytewise, Some)(input)? } else { (input, None) }; - let (input, app_permissions) = if bitmap[3] { + let (input, app_permissions) = if bitmap[2] { map(ieee1609dot2::SequenceOfPsidSsp::decode_bytewise, Some)(input)? } else { (input, None) }; - let (input, cert_issue_permissions) = if bitmap[4] { + let (input, cert_issue_permissions) = if bitmap[3] { map( ieee1609dot2::SequenceOfPsidGroupPermissions::decode_bytewise, Some, @@ -2996,7 +2719,7 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::ToBeSignedCertificate<'s> { } else { (input, None) }; - let (input, cert_request_permissions) = if bitmap[5] { + let (input, cert_request_permissions) = if bitmap[4] { map( ieee1609dot2::SequenceOfPsidGroupPermissions::decode_bytewise, Some, @@ -3004,8 +2727,8 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::ToBeSignedCertificate<'s> { } else { (input, None) }; - let (input, can_request_rollover) = (input, bitmap[6].then_some(())); - let (input, encryption_key) = if bitmap[7] { + let (input, can_request_rollover) = (input, bitmap[5].then_some(())); + let (input, encryption_key) = if bitmap[6] { map(ieee1609dot2::PublicEncryptionKey::decode_bytewise, Some)(input)? } else { (input, None) @@ -3015,12 +2738,11 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::ToBeSignedCertificate<'s> { let (input, flags, app_extensions, cert_issue_extensions, cert_request_extension) = if extended { let (input, bitmap) = decode_bytewise_bitstring(Some(0), None, false, input)?; + + #[allow(clippy::get_first, reason = "similarity to subsequent lines")] let (input, flags) = if bitmap.get(0).is_some_and(|bit| *bit) { - decode_bytewise_open_type( - |i| decode_bytewise_bitstring(Some(8), Some(8), false, i), - input, - ) - .map(|(rem, flags)| (rem, Some(Bits::<8>(flags))))? + decode_bytewise_open_type(ieee1609dot2::BitString::<8>::decode_bytewise, input) + .map(|(rem, flags)| (rem, Some(flags)))? } else { (input, None) }; @@ -3052,11 +2774,14 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::ToBeSignedCertificate<'s> { } else { (input, None) }; + + // consume unknown extensions for bit in bitmap.get(4..).unwrap_or_default() { if *bit { input = decode_bytewise_octetstring(Some(0), None, false, input)?.0; } } + ( input, flags, @@ -3230,7 +2955,8 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::LinkageData<'s> { where Self: Sized, { - let (input, bitmap) = decode_bytewise_bitstring(Some(1), Some(1), false, input)?; + let (input, (_, bitmap)) = decode_bytewise_sequence_preamble(false, 1, input)?; + let (input, i_cert) = ieee1609dot2::IValue::decode_bytewise(input)?; let (input, linkage_value) = ieee1609dot2::LinkageValue::decode_bytewise(input)?; let (input, group_linkage_value) = if bitmap[0] { @@ -3254,7 +2980,8 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::PsidGroupPermissions<'s> { where Self: Sized, { - let (input, bitmap) = decode_bytewise_bitstring(Some(3), Some(3), false, input)?; + let (input, (_, bitmap)) = decode_bytewise_sequence_preamble(false, 3, input)?; + let (input, subject_permissions) = ieee1609dot2::SubjectPermissions::decode_bytewise(input)?; let (input, min_chain_length) = if bitmap[0] { @@ -3272,7 +2999,9 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::PsidGroupPermissions<'s> { } else { ( input, - ieee1609dot2::EndEntityType(crate::bits![1, 0, 0, 0, 0, 0, 0, 0]), + ieee1609dot2::EndEntityType::from([ + true, false, false, false, false, false, false, false, + ]), ) }; Ok(( @@ -3293,7 +3022,7 @@ impl<'s> InternalDecode<'s> for ieee1609dot2::EndEntityType { Self: Sized, { let (input, bitstring) = decode_bytewise_bitstring(Some(8), Some(8), false, input)?; - Ok((input, Self(Bits(bitstring)))) + Ok((input, bitstring.into())) } } @@ -3343,41 +3072,82 @@ mod tests { use super::*; #[test] - fn decode_bool() { - assert!( - bool::decode_bitwise(BSlice(bitvec::prelude::bits![u8, Msb0; 1])) - .unwrap() - .1 + fn decodes_integer() { + assert_eq!(1u16, u16::decode_bytewise(&[0x00, 0x01]).unwrap().1); + + assert_eq!(1i16, i16::decode_bytewise(&[0x00, 0x01]).unwrap().1); + assert_eq!(-1i16, i16::decode_bytewise(&[0xFF, 0xFF]).unwrap().1); + + assert_eq!( + 1u32, + u32::decode_bytewise(&[0x00, 0x00, 0x00, 0x01]).unwrap().1 ); - assert!( - !bool::decode_bitwise(BSlice(bitvec::prelude::bits![u8, Msb0; 0])) - .unwrap() - .1 + assert_eq!( + 0x1234_5678_u32, + u32::decode_bytewise(&[0x12, 0x34, 0x56, 0x78]).unwrap().1 ); } #[test] - fn decodes_integer() { + fn decodes_traffic_class() { + let (_, output) = en302636_4_1::TrafficClass::decode_bytewise(&[0x82]).unwrap(); assert_eq!( - 1u8, - read_as_uint::(1)(BSlice(bitvec::prelude::bits![static u8, Msb0; 1])) - .unwrap() - .1 + en302636_4_1::TrafficClass { + store_carry_forward: true, + channel_offload: false, + traffic_class_id: u6::from_u8(0x02) + }, + output ); + + let (_, output) = en302636_4_1::TrafficClass::decode_bytewise(&[0x42]).unwrap(); assert_eq!( - 1u8, - read_as_uint::(3)(BSlice(bitvec::prelude::bits![static u8, Msb0; 0,0,1])) - .unwrap() - .1 + en302636_4_1::TrafficClass { + store_carry_forward: false, + channel_offload: true, + traffic_class_id: u6::from_u8(0x02) + }, + output ); + + let (_, output) = en302636_4_1::TrafficClass::decode_bytewise(&[0x3f]).unwrap(); assert_eq!( - 9u16, - read_as_uint::(4)(BSlice(bitvec::prelude::bits![static u8, Msb0; 1,0,0,1])) - .unwrap() - .1 + en302636_4_1::TrafficClass { + store_carry_forward: false, + channel_offload: false, + traffic_class_id: u6::from_u8(0x3f) + }, + output ); } + #[test] + fn decodes_oer_bitstring() { + let ref_val = vec![true]; + let oer_input = &[0x80]; + let (_, decoded) = decode_bytewise_bitstring(Some(1), Some(1), false, oer_input).unwrap(); + assert_eq!(ref_val, decoded); + + let ref_val = vec![false, true, false, false, false, false, true, false]; + let oer_input = &[0x42]; + let (_, decoded) = decode_bytewise_bitstring(Some(8), Some(8), false, oer_input).unwrap(); + assert_eq!(ref_val, decoded); + let (_, decoded) = ieee1609dot2::BitString::<8>::decode_bytewise(oer_input).unwrap(); + assert_eq!(ref_val, decoded.0); + + let ref_val = vec![false, true]; + let oer_input = &[2, 6, 0x42]; + let (_, decoded) = decode_bytewise_bitstring(None, None, true, oer_input).unwrap(); + assert_eq!(ref_val, decoded); + + let ref_val = vec![ + true, false, false, false, false, false, false, false, false, true, + ]; + let oer_input = &[3, 6, 0x80, 0x40]; + let (_, decoded) = decode_bytewise_bitstring(None, None, true, oer_input).unwrap(); + assert_eq!(ref_val, decoded); + } + #[test] fn decodes_basic_header() { let data: &'static [u8] = &[ @@ -3391,13 +3161,13 @@ mod tests { result, Decoded { bytes_consumed: 4, - decoded: en302636_4_1::BasicHeader { - version: 1, - next_header: en302636_4_1::NextAfterBasic::SecuredPacket, - reserved: crate::bits!(0;8), - lifetime: en302636_4_1::Lifetime(21), - remaining_hop_limit: 1 - } + decoded: en302636_4_1::BasicHeader::try_new( + 1, + en302636_4_1::NextAfterBasic::SecuredPacket, + en302636_4_1::Lifetime(21), + 1 + ) + .unwrap() } ); } @@ -3622,4 +3392,98 @@ mod tests { } ); } + + #[test] + // test to ensure proper encoding of BIT STRING data + fn round_trip_to_be_signed_certificate() { + let ref_bytes = &[ + 0xb0, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x81, 0xd9, 0x85, 0x86, 0x00, 0x01, + 0xe0, 0x01, 0x07, 0x80, 0x01, 0x24, 0x81, 0x04, 0x03, 0x01, 0xff, 0xfc, 0x80, 0x01, + 0x25, 0x81, 0x05, 0x04, 0x01, 0xff, 0xff, 0xff, 0x80, 0x01, 0x8c, 0x81, 0x05, 0x04, + 0x02, 0xff, 0xff, 0xe0, 0x00, 0x01, 0x8d, 0x80, 0x02, 0x02, 0x7e, 0x81, 0x02, 0x01, + 0x01, 0x80, 0x02, 0x02, 0x7f, 0x81, 0x02, 0x01, 0x01, 0x00, 0x02, 0x03, 0xff, 0x80, + 0x80, 0x82, 0x13, 0x43, 0x08, 0xc4, 0x32, 0x4d, 0x5f, 0x47, 0xfc, 0xbe, 0x66, 0x5f, + 0xb5, 0x5b, 0x40, 0x98, 0xb3, 0x8b, 0x9c, 0xaa, 0x48, 0x4b, 0xd4, 0x47, 0x4c, 0x6c, + 0x52, 0x16, 0x00, 0xa7, 0x50, 0x8c, + 0x02, // extension addition presence bitmap: length determinant + 0x04, // extension addition presence bitmap: how many unused bits -> 4 + 0x80, // extension addition presence bitmap: bitmap -> ext. 1 present, 2-4 not present + 0x01, // open type encoding: length + 0x80, // fixed size BIT STRING: 0b1000.0000 + ]; + + let data = ieee1609dot2::ToBeSignedCertificate { + id: ieee1609dot2::CertificateId::None(()), + craca_id: ieee1609dot2::HashedId3(&[0, 0, 0]), + crl_series: ieee1609dot2::Uint16(0), + validity_period: ieee1609dot2::ValidityPeriod { + start: ieee1609dot2::Uint32(612_489_605), + duration: ieee1609dot2::Duration::Years(ieee1609dot2::Uint16(1)), + }, + region: None, + assurance_level: Some(ieee1609dot2::SubjectAssurance(&[224])), + app_permissions: Some(ieee1609dot2::SequenceOfPsidSsp(vec![ + ieee1609dot2::PsidSsp { + psid: ieee1609dot2::Psid(36), + ssp: Some(ieee1609dot2::ServiceSpecificPermissions::BitmapSsp( + ieee1609dot2::BitmapSsp(&[1, 255, 252]), + )), + }, + ieee1609dot2::PsidSsp { + psid: ieee1609dot2::Psid(37), + ssp: Some(ieee1609dot2::ServiceSpecificPermissions::BitmapSsp( + ieee1609dot2::BitmapSsp(&[1, 255, 255, 255]), + )), + }, + ieee1609dot2::PsidSsp { + psid: ieee1609dot2::Psid(140), + ssp: Some(ieee1609dot2::ServiceSpecificPermissions::BitmapSsp( + ieee1609dot2::BitmapSsp(&[2, 255, 255, 224]), + )), + }, + ieee1609dot2::PsidSsp { + psid: ieee1609dot2::Psid(141), + ssp: None, + }, + ieee1609dot2::PsidSsp { + psid: ieee1609dot2::Psid(638), + ssp: Some(ieee1609dot2::ServiceSpecificPermissions::BitmapSsp( + ieee1609dot2::BitmapSsp(&[1]), + )), + }, + ieee1609dot2::PsidSsp { + psid: ieee1609dot2::Psid(639), + ssp: Some(ieee1609dot2::ServiceSpecificPermissions::BitmapSsp( + ieee1609dot2::BitmapSsp(&[1]), + )), + }, + ieee1609dot2::PsidSsp { + psid: ieee1609dot2::Psid(1023), + ssp: None, + }, + ])), + cert_issue_permissions: None, + cert_request_permissions: None, + can_request_rollover: None, + encryption_key: None, + verify_key_indicator: ieee1609dot2::VerificationKeyIndicator::VerificationKey( + ieee1609dot2::PublicVerificationKey::EcdsaNistP256( + ieee1609dot2::EccP256CurvePoint::CompressedY0(&[ + 19, 67, 8, 196, 50, 77, 95, 71, 252, 190, 102, 95, 181, 91, 64, 152, 179, + 139, 156, 170, 72, 75, 212, 71, 76, 108, 82, 22, 0, 167, 80, 140, + ]), + ), + ), + flags: Some(vec![true, false, false, false, false, false, false, false].into()), + app_extensions: None, + cert_issue_extensions: None, + cert_request_extension: None, + }; + + let decoded = ieee1609dot2::ToBeSignedCertificate::decode_bytewise(ref_bytes).unwrap(); + pretty_assertions::assert_eq!(data, decoded.1); + + let bytes = data.encode_to_vec().unwrap(); + assert_eq!(*ref_bytes, *bytes); + } } diff --git a/src/encode.rs b/src/encode.rs index 15c32a9..7b862a0 100644 --- a/src/encode.rs +++ b/src/encode.rs @@ -1,12 +1,12 @@ extern crate alloc; -use core::fmt::Display; - -use crate::{decode::BitwiseDecodable, util::write_into_vec_left_padded}; -use bitvec::prelude::*; -use num::Integer; +use arbitrary_int::{traits::Integer, u10, u6}; use num_traits::ToBytes; +#[cfg(not(feature = "json"))] +use alloc::vec; + +#[allow(clippy::wildcard_imports)] use super::*; #[derive(Debug)] @@ -31,35 +31,19 @@ impl EncodeError { #[derive(Debug, Default)] pub struct Encoder { - bits: BitVec, + bytes: Vec, } impl Encoder { #[must_use] pub fn new() -> Self { - Self { - bits: bitvec![u8, Msb0;], - } + Self::default() } } impl From for alloc::vec::Vec { fn from(val: Encoder) -> Self { - let mut vec = alloc::vec![]; - write_into_vec_left_padded(val.bits.bitwise(), &mut vec); - vec - } -} - -impl From for bytes::Bytes { - fn from(val: Encoder) -> Self { - >>::into(val).into() - } -} - -impl From for BitVec { - fn from(val: Encoder) -> Self { - val.bits + val.bytes } } @@ -115,88 +99,190 @@ pub trait Encode { } } -impl Encode for bool { +trait BitwiseWrite { + fn write_bitwise(&self, bit_count: usize, output: &mut Vec); +} + +macro_rules! write_int_bitwise { + ($typ:ty, $max_bits:expr) => { + impl BitwiseWrite for $typ { + fn write_bitwise(&self, bit_count: usize, output: &mut Vec) { + for idx in (0..bit_count).rev() { + let bit = ((self >> idx) & 0x01) == 1; + output.push(bit) + } + } + } + }; +} + +write_int_bitwise!(u8, 8); +write_int_bitwise!(u16, 16); +write_int_bitwise!(i16, 16); +write_int_bitwise!(u32, 32); +write_int_bitwise!(i32, 32); + +trait BitwiseEncode { + fn encode_bitwise(&self, output: &mut Vec); +} + +impl BitwiseEncode for bool { + fn encode_bitwise(&self, output: &mut Vec) { + output.push(*self); + } +} + +macro_rules! encode_int { + ($typ:ty) => { + impl Encode for $typ { + fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { + let bytes = self.to_be_bytes(); + output.bytes.extend_from_slice(&bytes); + Ok(()) + } + } + }; +} + +encode_int!(u16); +encode_int!(i16); +encode_int!(u32); +encode_int!(i32); + +impl Encode for u8 { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - output.bits.push(*self); + output.bytes.push(*self); Ok(()) } } -#[allow(clippy::unnecessary_wraps, reason = "common interface")] -fn write_as_int( - integer: &I, - bit_count: usize, - output: &mut Encoder, -) -> Result<(), EncodeError> { - let bytes = integer.to_be_bytes(); - let bits = bytes.as_bits::(); - output - .bits - .extend_from_bitslice(&bits[(bits.len() - bit_count)..bits.len()]); - Ok(()) +impl BitwiseEncode for u10 { + fn encode_bitwise(&self, output: &mut Vec) { + self.as_u16().write_bitwise(10, output); + } +} + +impl BitwiseEncode for u4 { + fn encode_bitwise(&self, output: &mut Vec) { + self.as_u8().write_bitwise(4, output); + } } -impl Encode for Bits { +impl BitwiseEncode for i15 { + fn encode_bitwise(&self, output: &mut Vec) { + self.as_i16().write_bitwise(15, output); + } +} + +impl BitwiseEncode for u6 { + fn encode_bitwise(&self, output: &mut Vec) { + self.as_u8().write_bitwise(6, output); + } +} + +impl Encode for [u8; SIZE] { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - output.bits.extend_from_bitslice(&self.0); + output.bytes.extend_from_slice(self); Ok(()) } } -impl Encode for [u8; SIZE] { +impl Encode for [bool; 8] { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - output.bits.extend_from_bitslice(self.view_bits::()); + let byte = (u8::from(self[0]) << 7) + + (u8::from(self[1]) << 6) + + (u8::from(self[2]) << 5) + + (u8::from(self[3]) << 4) + + (u8::from(self[4]) << 3) + + (u8::from(self[5]) << 2) + + (u8::from(self[6]) << 1) + + (u8::from(self[7])); + + output.bytes.push(byte); Ok(()) } } +impl Encode for Vec { + /// Encode a bool-vector which is a multiple of 8 + fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { + if self.len().is_multiple_of(8) { + for bits in self.chunks(8) { + // expect shouldn't be reachable since we checked the length to be a multiple of 8 + let bits: [bool; 8] = bits + .try_into() + .expect("Array chunk suddenly returned different size"); + bits.encode(output)?; + } + + Ok(()) + } else { + Err(EncodeError::Common(alloc::format!( + "Can't encode {} bits to bytes (only multiples of 8 allowed)", + self.len() + ))) + } + } +} + impl Encode for &'_ [u8] { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - output.bits.extend_from_bitslice(self.as_bits::()); + output.bytes.extend_from_slice(self); Ok(()) } } impl Encode for en302636_4_1::Lifetime { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - write_as_int(&self.0, 8, output) + self.0.encode(output) } } impl Encode for en302636_4_1::Timestamp { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - write_as_int(&self.0, 32, output) + self.0.encode(output) } } -impl Encode for en302636_4_1::StationType { - fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - write_as_int(&(*self as u8), 5, output) +impl BitwiseEncode for en302636_4_1::StationType { + fn encode_bitwise(&self, output: &mut Vec) { + let val = *self as u8; + val.write_bitwise(5, output); } } impl Encode for en302636_4_1::Address { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - self.manually_configured.encode(output)?; - self.station_type.encode(output)?; - self.reserved.encode(output)?; + let mut bv = vec![]; + self.manually_configured.encode_bitwise(&mut bv); // 1 bit + self.station_type.encode_bitwise(&mut bv); // 5 bit + self.reserved.encode_bitwise(&mut bv); // 10 bit + bv.encode(output)?; + self.address.encode(output) } } -impl Encode for en302636_4_1::NextAfterBasic { - fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - write_as_int(&(*self as u8), 4, output) +impl BitwiseEncode for en302636_4_1::NextAfterBasic { + fn encode_bitwise(&self, output: &mut Vec) { + let val = *self as u8; + val.write_bitwise(4, output); } } impl Encode for en302636_4_1::BasicHeader { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - write_as_int(&self.version, 4, output)?; - self.next_header.encode(output)?; + let mut bv = vec![]; + self.version.encode_bitwise(&mut bv); // 4 bit + self.next_header.encode_bitwise(&mut bv); // 4 bit + + // we can safely assume 8 bits since we added them before + let bits: [bool; 8] = bv.try_into().expect("Bit vector suddenly not 8 bits"); + bits.encode(output)?; + self.reserved.encode(output)?; self.lifetime.encode(output)?; - write_as_int(&self.remaining_hop_limit, 8, output) + self.remaining_hop_limit.encode(output) } } @@ -204,11 +290,15 @@ impl Encode for en302636_4_1::LongPositionVector { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { self.gn_address.encode(output)?; self.timestamp.encode(output)?; - write_as_int(&self.latitude, 32, output)?; - write_as_int(&self.longitude, 32, output)?; - self.position_accuracy.encode(output)?; - write_as_int(&self.speed, 15, output)?; - write_as_int(&self.heading, 16, output) + self.latitude.encode(output)?; + self.longitude.encode(output)?; + + let mut bv = vec![]; + self.position_accuracy.encode_bitwise(&mut bv); // 1 bit + self.speed.encode_bitwise(&mut bv); // 15 bits + bv.encode(output)?; + + self.heading.encode(output) } } @@ -216,29 +306,35 @@ impl Encode for en302636_4_1::ShortPositionVector { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { self.gn_address.encode(output)?; self.timestamp.encode(output)?; - write_as_int(&self.latitude, 32, output)?; - write_as_int(&self.longitude, 32, output) + self.latitude.encode(output)?; + self.longitude.encode(output) } } impl Encode for en302636_4_1::TrafficClass { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - self.store_carry_forward.encode(output)?; - self.channel_offload.encode(output)?; - write_as_int(&self.traffic_class_id, 6, output) + let mut bv = vec![]; + self.store_carry_forward.encode_bitwise(&mut bv); // 1 bit + self.channel_offload.encode_bitwise(&mut bv); // 1 bit + self.traffic_class_id.encode_bitwise(&mut bv); // 6 bit + + // we can safely assume 8 bits since we added them before + let bits: [bool; 8] = bv.try_into().expect("Bit vector suddenly not 8 bits"); + bits.encode(output) } } -impl Encode for en302636_4_1::NextAfterCommon { - fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - write_as_int(&(*self as u8), 4, output) +impl BitwiseEncode for en302636_4_1::NextAfterCommon { + fn encode_bitwise(&self, output: &mut Vec) { + let val = *self as u8; + val.write_bitwise(4, output); } } impl Encode for en302636_4_1::HeaderType { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { let (ty, subty) = match self { - en302636_4_1::HeaderType::Any => (0, 0), + en302636_4_1::HeaderType::Any => (0u8, 0u8), en302636_4_1::HeaderType::Beacon => (1, 0), en302636_4_1::HeaderType::GeoUnicast => (2, 0), en302636_4_1::HeaderType::GeoAnycast(en302636_4_1::AreaType::Circular) => (3, 0), @@ -256,41 +352,56 @@ impl Encode for en302636_4_1::HeaderType { ) => (6, 0), en302636_4_1::HeaderType::LocationService(_) => (6, 1), }; - write_as_int(&ty, 4, output)?; - write_as_int(&subty, 4, output) + + let mut bv = vec![]; + ty.write_bitwise(4, &mut bv); + subty.write_bitwise(4, &mut bv); + + // we can safely assume 8 bits since we added them before + let bits: [bool; 8] = bv.try_into().expect("Bit vector suddenly not 8 bits"); + bits.encode(output) } } impl Encode for en302636_4_1::CommonHeader { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - self.next_header.encode(output)?; - self.reserved_1.encode(output)?; + { + let mut bv = vec![]; + + self.next_header.encode_bitwise(&mut bv); // 4 bit + self.reserved_1.encode_bitwise(&mut bv); // 4 bit + + // we can safely assume 8 bits since we added them before + let bits: [bool; 8] = bv.try_into().expect("Bit vector suddenly not 8 bits"); + bits.encode(output)?; + } + self.header_type_and_subtype.encode(output)?; self.traffic_class.encode(output)?; self.flags.encode(output)?; - write_as_int(&self.payload_length, 16, output)?; - write_as_int(&self.maximum_hop_limit, 8, output)?; + self.payload_length.encode(output)?; + self.maximum_hop_limit.encode(output)?; self.reserved_2.encode(output) } } impl Encode for en302636_4_1::GeoAnycast { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - write_as_int(&self.sequence_number, 16, output)?; + self.sequence_number.encode(output)?; self.reserved_1.encode(output)?; self.source_position_vector.encode(output)?; - write_as_int(&self.geo_area_position_latitude, 32, output)?; - write_as_int(&self.geo_area_position_longitude, 32, output)?; - write_as_int(&self.distance_a, 16, output)?; - write_as_int(&self.distance_b, 16, output)?; - write_as_int(&self.angle, 16, output)?; + self.geo_area_position_latitude.encode(output)?; + self.geo_area_position_longitude.encode(output)?; + self.distance_a.encode(output)?; + self.distance_b.encode(output)?; + self.angle.encode(output)?; self.reserved_2.encode(output) } } impl Encode for en302636_4_1::GeoUnicast { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - write_as_int(&self.sequence_number, 16, output)?; + self.sequence_number.encode(output)?; self.reserved.encode(output)?; self.source_position_vector.encode(output)?; self.destination_position_vector.encode(output) @@ -299,7 +410,7 @@ impl Encode for en302636_4_1::GeoUnicast { impl Encode for en302636_4_1::TopologicallyScopedBroadcast { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - write_as_int(&self.sequence_number, 16, output)?; + self.sequence_number.encode(output)?; self.reserved.encode(output)?; self.source_position_vector.encode(output) } @@ -320,7 +431,7 @@ impl Encode for en302636_4_1::Beacon { impl Encode for en302636_4_1::LSRequest { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - write_as_int(&self.sequence_number, 16, output)?; + self.sequence_number.encode(output)?; self.reserved.encode(output)?; self.source_position_vector.encode(output)?; self.request_gn_address.encode(output) @@ -329,7 +440,7 @@ impl Encode for en302636_4_1::LSRequest { impl Encode for en302636_4_1::LSReply { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - write_as_int(&self.sequence_number, 16, output)?; + self.sequence_number.encode(output)?; self.reserved.encode(output)?; self.source_position_vector.encode(output)?; self.destination_position_vector.encode(output) @@ -373,20 +484,18 @@ impl Encode for Packet<'_> { } } -// ::::::::::: :::::::::: :::::::::: :::::::::: ::: :::::::: ::::::: :::::::: :::::::: -// :+: :+: :+: :+: :+:+: :+: :+: :+: :+: :+: :+: :+: :+: -// +:+ +:+ +:+ +:+ +:+ +:+ +:+ :+:+ +:+ +:+ +:+ -// +#+ +#++:++# +#++:++# +#++:++# +#+ +#++:++#+ +#+ + +:+ +#++:++#+ +#+ -// +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+# +#+ +#+ +#+ -// #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# -// ########### ########## ########## ########## ####### ######## ####### ######## ### ########## +// ===================================================== +// ETSI TS 103 097/ IEEE 1609.2 +// ===================================================== #[allow(clippy::unnecessary_wraps, reason = "common interface")] fn encode_oer_length(length: usize, output: &mut Encoder) -> Result<(), EncodeError> { match length { len if len < 128 => { #[allow(clippy::cast_possible_truncation)] - output.bits.extend_from_raw_slice(&[len as u8]); + let value = len as u8; + + output.bytes.push(value); Ok(()) } len => { @@ -396,16 +505,16 @@ fn encode_oer_length(length: usize, output: &mut Encoder) -> Result<(), EncodeEr length_bytes = &length_bytes[1..]; } #[allow(clippy::cast_possible_truncation)] - output - .bits - .extend_from_raw_slice(&[(length_bytes.len() + 128) as u8]); - output.bits.extend_from_raw_slice(length_bytes); + let len_byte = 0x80 | (length_bytes.len() as u8); + + output.bytes.push(len_byte); + output.bytes.extend_from_slice(length_bytes); Ok(()) } } } -fn encode_oer_integer( +fn encode_oer_integer( min: Option, max: Option, value: &I, @@ -413,9 +522,7 @@ fn encode_oer_integer( ) -> Result<(), EncodeError> { match (min, max) { (Some(_), Some(_)) => { - output - .bits - .extend_from_raw_slice(value.to_be_bytes().as_ref()); + output.bytes.extend_from_slice(value.to_be_bytes().as_ref()); Ok(()) } (Some(min), _) if min >= 0 => { @@ -424,8 +531,9 @@ fn encode_oer_integer( while bytes.len() > 1 && bytes[0] == 0 { bytes = &bytes[1..]; } + encode_oer_length(bytes.len(), output)?; - output.bits.extend_from_raw_slice(bytes); + output.bytes.extend_from_slice(bytes); Ok(()) } _ => Err(EncodeError::Unsupported( @@ -446,61 +554,62 @@ fn encode_oer_octetstring( ) -> Result<(), EncodeError> { match (min, max) { (Some(min), Some(max)) if min == max => { - output.bits.extend_from_raw_slice(value); + output.bytes.extend_from_slice(value); Ok(()) } _ => { encode_oer_length(value.len(), output)?; - output.bits.extend_from_raw_slice(value); + output.bytes.extend_from_slice(value); Ok(()) } } } #[allow(clippy::unnecessary_wraps, reason = "common interface")] -fn encode_oer_fixed_bitstring( - value: &BitVec, - output: &mut Encoder, -) -> Result<(), EncodeError> { - output.bits.extend_from_bitslice(value); - for _ in 0..(8 - value.len() % 8) { - output.bits.push(false); - } +fn encode_oer_fixed_bitstring(value: &[bool], output: &mut Encoder) -> Result<(), EncodeError> { + let mut bv = value.to_vec(); + bv.extend_from_slice(&vec![false; util::bitstring_padding_bits(bv.len())]); // add padding to multiples of 8 + bv.encode(output)?; + Ok(()) } +// ASN.1 OER "bitstring" values and the "extension addition presence bitmap" fn encode_oer_varlength_bitstring(value: &[bool], output: &mut Encoder) -> Result<(), EncodeError> { - encode_oer_length(Integer::div_ceil(&value.len(), &8usize) + 1, output)?; - #[allow(clippy::cast_possible_truncation)] - let unused_bits = 8 - value.len() % 8; + encode_oer_length(util::bitstring_buffer_size(value.len()) + 1, output)?; + + let unused_bits = util::bitstring_padding_bits(value.len()); + + // Note: using integer encoding is not 100% correct, but leads to same result in this case #[allow(clippy::cast_possible_truncation)] encode_oer_integer(Some(0), Some(8), &(unused_bits as u8), output)?; - for bit in value { - output.bits.push(*bit); - } - for _ in 0..unused_bits { - output.bits.push(false); - } + + let mut bv = value.to_vec(); + bv.extend_from_slice(&vec![false; util::bitstring_padding_bits(bv.len())]); // add padding to multiples of 8 + bv.encode(output)?; + Ok(()) } +/// Build ASN.1 SEQUENCE preamble +/// +/// Extension bit is optional +#[allow(clippy::unnecessary_wraps, reason = "common interface")] fn encode_extension_and_optional_bitmap( - is_extended: bool, + extension: Option, bitmap: &[bool], output: &mut Encoder, ) -> Result<(), EncodeError> { - output.bits.push(is_extended); - for bit in bitmap { - output.bits.push(*bit); - } - if bitmap.len() > 7 { - return Err(EncodeError::Unsupported( - "Optional bitmaps longer than 7 bits are unsupported!".into(), - )); - } - for _ in 0..(7 - bitmap.len()) { - output.bits.push(false); + let mut bv = vec![]; + + if let Some(is_extended) = extension { + bv.push(is_extended); } + + bv.extend_from_slice(bitmap); + bv.extend_from_slice(&vec![false; util::bitstring_padding_bits(bv.len())]); // add padding to multiples of 8 + bv.encode(output)?; + Ok(()) } @@ -518,6 +627,12 @@ fn encode_oer_open_type(value: &T, output: &mut Encoder) -> Result<() encode_oer_octetstring(Some(0), None, &bytes, output) } +impl Encode for ieee1609dot2::BitString { + fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { + encode_oer_fixed_bitstring(&self.0, output) + } +} + macro_rules! encode_int { ($typ:ty, $min:expr, $max:expr) => { impl Encode for $typ { @@ -548,13 +663,9 @@ encode_int!(ieee1609dot2::Psid, Some(0), None); impl Encode for ieee1609dot2::CertificateBase<'_> { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - encode_oer_fixed_bitstring( - &self - .signature - .as_ref() - .map_or(bitvec![u8, Msb0; 0], |_| bitvec![u8, Msb0; 1]), - output, - )?; + let bitmap = [self.signature.is_some()]; + encode_extension_and_optional_bitmap(None, &bitmap, output)?; + self.version.encode(output)?; self.r_type.encode(output)?; self.issuer.encode(output)?; @@ -635,7 +746,8 @@ impl Encode for ieee1609dot2::ToBeSignedCertificate<'_> { self.can_request_rollover.is_some(), self.encryption_key.is_some(), ]; - encode_extension_and_optional_bitmap(is_extended, &bitmap, output)?; + encode_extension_and_optional_bitmap(Some(is_extended), &bitmap, output)?; + self.id.encode(output)?; self.craca_id.encode(output)?; self.crl_series.encode(output)?; @@ -670,12 +782,9 @@ impl Encode for ieee1609dot2::ToBeSignedCertificate<'_> { } else { Ok(()) }?; - self.flags.as_ref().map_or(Ok(()), |flags| { - let mut encoder = Encoder::new(); - encode_oer_fixed_bitstring(&flags.0, &mut encoder).and_then(|()| { - encode_oer_octetstring(Some(0), None, &Into::>::into(encoder), output) - }) - })?; + self.flags + .as_ref() + .map_or(Ok(()), |flags| encode_oer_open_type(flags, output))?; self.app_extensions .as_ref() .map_or(Ok(()), |app_ext| encode_oer_open_type(app_ext, output))?; @@ -781,9 +890,13 @@ impl Encode for ieee1609dot2::PsidGroupPermissions<'_> { let bitmap = [ self.min_chain_length == 1, self.chain_length_range == 0, - self.ee_type == ieee1609dot2::EndEntityType(crate::bits!(1, 0, 0, 0, 0, 0, 0, 0)), + self.ee_type + == ieee1609dot2::EndEntityType::from([ + true, false, false, false, false, false, false, false, + ]), ]; - encode_oer_fixed_bitstring(&bitmap.iter().collect::>(), output)?; + encode_extension_and_optional_bitmap(None, &bitmap, output)?; + self.subject_permissions.encode(output)?; if bitmap[0] { encode_oer_integer(Some(0), None, &self.min_chain_length, output) @@ -806,16 +919,15 @@ impl Encode for ieee1609dot2::PsidGroupPermissions<'_> { impl Encode for ieee1609dot2::EndEntityType { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - encode_oer_fixed_bitstring(&self.0 .0, output) + self.0.encode(output) } } impl Encode for ieee1609dot2::PsidSsp<'_> { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - match self.ssp { - Some(_) => encode_oer_fixed_bitstring(&bitvec![u8, Msb0; 1], output), - None => encode_oer_fixed_bitstring(&bitvec![u8, Msb0; 0], output), - }?; + let bitmap = [self.ssp.is_some()]; + encode_extension_and_optional_bitmap(None, &bitmap, output)?; + self.psid.encode(output)?; self.ssp.as_ref().map_or(Ok(()), |ssp| ssp.encode(output)) } @@ -823,10 +935,9 @@ impl Encode for ieee1609dot2::PsidSsp<'_> { impl Encode for ieee1609dot2::PsidSspRange<'_> { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - match self.ssp_range { - Some(_) => encode_oer_fixed_bitstring(&bitvec![u8, Msb0; 1], output), - None => encode_oer_fixed_bitstring(&bitvec![u8, Msb0; 0], output), - }?; + let bitmap = [self.ssp_range.is_some()]; + encode_extension_and_optional_bitmap(None, &bitmap, output)?; + self.psid.encode(output)?; self.ssp_range .as_ref() @@ -1136,10 +1247,9 @@ impl Encode for ieee1609dot2::Hostname { impl Encode for ieee1609dot2::LinkageData<'_> { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - match self.group_linkage_value { - Some(_) => encode_oer_fixed_bitstring(&bitvec![u8, Msb0; 1], output), - None => encode_oer_fixed_bitstring(&bitvec![u8, Msb0; 0], output), - }?; + let bitmap = [self.group_linkage_value.is_some()]; + encode_extension_and_optional_bitmap(None, &bitmap, output)?; + self.i_cert.encode(output)?; self.linkage_value.encode(output)?; self.group_linkage_value @@ -1281,7 +1391,8 @@ impl Encode for ieee1609dot2::AnonymousContributedExtensionBlockExtns<'_> { impl Encode for ieee1609dot2::SignedDataPayload<'_> { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { let bitmap = [self.data.is_some(), self.ext_data_hash.is_some()]; - encode_extension_and_optional_bitmap(self.omitted.is_some(), &bitmap, output)?; + encode_extension_and_optional_bitmap(Some(self.omitted.is_some()), &bitmap, output)?; + self.data .as_ref() .map_or(Ok(()), |data| data.encode(output))?; @@ -1325,7 +1436,8 @@ impl Encode for ieee1609dot2::HeaderInfo<'_> { self.missing_crl_identifier.is_some(), self.encryption_key.is_some(), ]; - encode_extension_and_optional_bitmap(is_extended, &bitmap, output)?; + encode_extension_and_optional_bitmap(Some(is_extended), &bitmap, output)?; + self.psid.encode(output)?; self.generation_time .as_ref() @@ -1374,7 +1486,8 @@ impl Encode for ieee1609dot2::HeaderInfo<'_> { impl Encode for ieee1609dot2::MissingCrlIdentifier<'_> { fn encode(&self, output: &mut Encoder) -> Result<(), EncodeError> { - encode_extension_and_optional_bitmap(false, &[], output)?; + encode_extension_and_optional_bitmap(Some(false), &[], output)?; + self.craca_id.encode(output)?; self.crl_series.encode(output) } @@ -1413,4 +1526,69 @@ mod tests { >>::into(encoder).as_slice() ); } + + #[test] + fn encodes_oer_bitstring() { + let mut encoder = Encoder::new(); + encode_oer_fixed_bitstring(&[true], &mut encoder).unwrap(); + let output: Vec = encoder.into(); + assert_eq!(&[0x80], output.as_slice()); + + let mut encoder = Encoder::new(); + encode_oer_fixed_bitstring( + &[true, false, false, false, false, false, false, false], + &mut encoder, + ) + .unwrap(); + let output: Vec = encoder.into(); + assert_eq!(&[0x80], output.as_slice()); + + let mut encoder = Encoder::new(); + encode_oer_fixed_bitstring( + &[ + true, false, false, false, false, false, false, false, false, true, + ], + &mut encoder, + ) + .unwrap(); + let output: Vec = encoder.into(); + assert_eq!(&[0x80, 0x40], output.as_slice()); + + let mut encoder = Encoder::new(); + encode_oer_varlength_bitstring(&[true, false], &mut encoder).unwrap(); + let output: Vec = encoder.into(); + assert_eq!(&[2, 6, 0x80], output.as_slice()); + + let mut encoder = Encoder::new(); + encode_oer_varlength_bitstring( + &[true, false, false, false, false, false, false, false], + &mut encoder, + ) + .unwrap(); + let output: Vec = encoder.into(); + assert_eq!(&[2, 0, 0x80], output.as_slice()); + + let mut encoder = Encoder::new(); + encode_oer_varlength_bitstring( + &[ + true, false, false, false, false, false, false, false, false, true, + ], + &mut encoder, + ) + .unwrap(); + let output: Vec = encoder.into(); + assert_eq!(&[3, 6, 0x80, 0x40], output.as_slice()); + + let mut encoder = Encoder::new(); + encode_oer_varlength_bitstring( + &[ + true, false, false, false, false, false, false, false, false, true, false, false, + false, false, true, false, + ], + &mut encoder, + ) + .unwrap(); + let output: Vec = encoder.into(); + assert_eq!(&[3, 0, 0x80, 0x42], output.as_slice()); + } } diff --git a/src/lib.rs b/src/lib.rs index 72a0607..cb5bd3e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,44 +36,37 @@ //! use geonetworking::*; //! //! let packet = Packet::Unsecured { -//! basic: en302636_4_1::BasicHeader { -//! version: 1, -//! next_header: en302636_4_1::NextAfterBasic::CommonHeader, -//! reserved: bits![0; 8], -//! lifetime: en302636_4_1::Lifetime(80), -//! remaining_hop_limit: 1, -//! }, -//! common: en302636_4_1::CommonHeader { -//! next_header: en302636_4_1::NextAfterCommon::BTPB, -//! reserved_1: bits![0, 0, 0, 0], -//! header_type_and_subtype: en302636_4_1::HeaderType::TopologicallyScopedBroadcast( +//! basic: en302636_4_1::BasicHeader::try_new( +//! 1, +//! en302636_4_1::NextAfterBasic::CommonHeader, +//! en302636_4_1::Lifetime(80), +//! 1, +//! ).expect("Failed to create BasicHeader"), +//! common: en302636_4_1::CommonHeader::new( +//! en302636_4_1::NextAfterCommon::BTPB, +//! en302636_4_1::HeaderType::TopologicallyScopedBroadcast( //! en302636_4_1::BroadcastType::SingleHop, //! ), -//! traffic_class: en302636_4_1::TrafficClass { -//! store_carry_forward: false, -//! channel_offload: false, -//! traffic_class_id: 2, -//! }, -//! flags: bits![0, 0, 0, 0, 0, 0, 0, 0], -//! payload_length: 1, -//! maximum_hop_limit: 1, -//! reserved_2: bits![0, 0, 0, 0, 0, 0, 0, 0], -//! }, +//! en302636_4_1::TrafficClass::try_new(false, false, 2).expect("Failed to create TrafficClass"), +//! [false; 8], +//! 1, +//! 1, +//! ), //! extended: Some(en302636_4_1::ExtendedHeader::SHB(en302636_4_1::SingleHopBroadcast { -//! source_position_vector: en302636_4_1::LongPositionVector { -//! gn_address: en302636_4_1::Address { +//! source_position_vector: en302636_4_1::LongPositionVector::try_new( +//! en302636_4_1::Address { //! manually_configured: false, //! station_type: en302636_4_1::StationType::Unknown, -//! reserved: bits![0, 1, 0, 0, 0, 0, 0, 1, 1, 0], +//! reserved: arbitrary_int::u10::new(0x0106), //! address: [0, 96, 224, 105, 87, 141], //! }, -//! timestamp: en302636_4_1::Timestamp(542947520), -//! latitude: 535574568, -//! longitude: 99765648, -//! position_accuracy: false, -//! speed: 680, -//! heading: 2122, -//! }, +//! en302636_4_1::Timestamp(542947520), +//! 535574568, +//! 99765648, +//! false, +//! 680, +//! 2122, +//! ).expect("Failed to create LongPositionVector"), //! media_dependent_data: [127, 0, 184, 0], //! })), //! payload: &[42] @@ -119,8 +112,7 @@ use std::fmt::Debug; #[cfg(not(feature = "validate"))] use {alloc::vec::Vec, core::fmt::Debug}; -use bitvec::prelude::*; -use bytes::Bytes; +use arbitrary_int::{i15, u4}; mod decode; mod encode; @@ -138,76 +130,7 @@ pub use encode::{Encode, EncodeError, Encoder}; pub use validate::{Validate, ValidationError, ValidationResult}; #[cfg(feature = "json")] -use serde::{de::Visitor, Deserialize, Serialize}; - -#[cfg(feature = "json")] -struct BitsVisitor; - -#[cfg(feature = "json")] -impl<'de, const SIZE: usize> Visitor<'de> for BitsVisitor { - type Value = Bits; - - fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { - formatter.write_str("a sequence of boolean values") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: serde::de::SeqAccess<'de>, - { - let mut bits = vec![]; - while let Some(bit) = seq.next_element::()? { - bits.push(bit); - } - Ok(Bits(bits.iter().collect::>())) - } -} - -#[derive(Clone, PartialEq)] -pub struct Bits(pub BitVec); - -impl Debug for Bits { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - self.0.fmt(f) - } -} - -#[cfg(feature = "json")] -impl<'de, const SIZE: usize> Deserialize<'de> for Bits { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_seq(BitsVisitor::) - } -} - -#[cfg(feature = "json")] -impl Serialize for Bits { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.collect_seq(self.0.iter().map(|bit| *bit)) - } -} - -#[macro_export] -/// Shorthand to define a bit-vector "literal" -/// -/// This macro accepts: -/// -/// - a comma-separated list of 1s and 0s, like `bits![0, 0, 0, 0]` -/// - a value (1 or 0) and a length value (usize) separated by a semicolon, like `geonetworking::bits![0; 8]` -/// -macro_rules! bits { - ($val:expr; $len:expr) => { - Bits(bitvec::vec::BitVec::::repeat($val != 0, $len)) - }; - ($($val:expr),* $(,)?) => { - Bits(bitvec::prelude::bits![u8, bitvec::prelude::Msb0; $($val),*].to_bitvec()) - }; -} +use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize))] diff --git a/src/standards/en302636_4_1.rs b/src/standards/en302636_4_1.rs index 55ba1b2..8dce749 100644 --- a/src/standards/en302636_4_1.rs +++ b/src/standards/en302636_4_1.rs @@ -1,9 +1,9 @@ //! Message types from EN 302 636-4-1 extern crate alloc; -use crate::{bits, Bits}; use alloc::string::ToString; +use arbitrary_int::{i15, traits::Integer, u10, u4, u6}; #[cfg(feature = "json")] use serde::{Deserialize, Serialize}; @@ -90,18 +90,19 @@ fn make_heading(deg: f32) -> Result { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +// 8 byte in total pub struct Address { /// This bit allows distinguishing between manually configured network address (clause 10.2.1.3.3) (update) /// and the initial GeoNetworking address (clause 10.2.1.3.2). M is set to 1 if the address is manually configured otherwise it equals 0. - pub manually_configured: bool, + pub manually_configured: bool, // 1 bit /// ITS Station type - pub station_type: StationType, + pub station_type: StationType, // 5 bits /// Reserved - pub reserved: Bits<10>, + pub reserved: u10, // 10 bits /// Represents the `LL_ADDR` - pub address: [u8; 6], + pub address: [u8; 6], // 48 bits (6 byte) } impl Address { @@ -110,7 +111,7 @@ impl Address { Self { manually_configured, station_type, - reserved: bits![0;10], + reserved: u10::from_u16(0), address, } } @@ -135,6 +136,32 @@ pub enum StationType { RoadSideUnit = 15, } +impl TryFrom for StationType { + type Error = alloc::string::String; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::Unknown), + 1 => Ok(Self::Pedestrian), + 2 => Ok(Self::Cyclist), + 3 => Ok(Self::Moped), + 4 => Ok(Self::Motorcycle), + 5 => Ok(Self::PassengerCar), + 6 => Ok(Self::Bus), + 7 => Ok(Self::LightTruck), + 8 => Ok(Self::HeavyTruck), + 9 => Ok(Self::Trailer), + 10 => Ok(Self::SpecialVehicle), + 11 => Ok(Self::Tram), + 15 => Ok(Self::RoadSideUnit), + + i => Err(alloc::format!( + "No corresponding station type for value {i}!" + )), + } + } +} + /// Expresses the time in milliseconds at which the latitude and longitude /// of the ITS-S were acquired by the GeoAdhoc router. The time is encoded as: /// TST = TST(TAI) % 2^32 @@ -158,28 +185,29 @@ impl Timestamp { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +// 24 byte in total pub struct LongPositionVector { - pub gn_address: Address, + pub gn_address: Address, // 64 bits /// Expresses the time in milliseconds at which the latitude and longitude /// of the ITS-S were acquired by the GeoAdhoc router. The time is encoded as: /// TST = TST(TAI) % 2^32 /// where TST(TAI) is the number of elapsed TAI milliseconds since 2004-01-01 00:00:00.000 UTC - pub timestamp: Timestamp, + pub timestamp: Timestamp, // 32 bits /// WGS 84 [i.6] latitude of the GeoAdhoc router reference position expressed in 1/10 micro degree - pub latitude: i32, + pub latitude: i32, // 32 bits /// WGS 84 [i.6] longitude of the GeoAdhoc router reference position expressed in 1/10 micro degree - pub longitude: i32, + pub longitude: i32, // 32 bits /// Position accuracy indicator of the GeoAdhoc router reference position /// Set to 1 (i.e. True) if the semiMajorConfidence of the `PosConfidenceEllipse` as specified in ETSI TS 102 894-2 \[11\] /// is smaller than the GN protocol constant itsGnPaiInterval / 2 /// Set to 0 (i.e. False) otherwise - pub position_accuracy: bool, - /// Speed of the GeoAdhoc router expressed in signed units of 0,01 meter per second - pub speed: i16, - /// Heading of the GeoAdhoc router, expressed in unsigned units of 0,1 degree from North - pub heading: u16, + pub position_accuracy: bool, // 1 bit + /// Speed of the GeoAdhoc router expressed in signed units of 0.01 meter per second + pub speed: i15, // 15 bits + /// Heading of the GeoAdhoc router, expressed in unsigned units of 0.1 degree from North + pub heading: u16, // 16 bits } impl LongPositionVector { @@ -242,12 +270,8 @@ impl LongPositionVector { speed: i16, heading: u16, ) -> Result { - // speed value is 15 bit signed integer - if !(Self::SPEED_MIN..=Self::SPEED_MAX).contains(&speed) { - return Err(Error::ValueOutOfBounds(OutOfBoundsError::new( - "speed", "i15", - ))); - } + let speed = i15::try_new(speed) + .map_err(|_| Error::ValueOutOfBounds(OutOfBoundsError::new("speed", "i15")))?; Ok(Self { gn_address, @@ -272,7 +296,7 @@ impl LongPositionVector { #[must_use] pub fn get_speed_mps(&self) -> f32 { - f32::from(self.speed) / Self::MPS_TO_INT_FACTOR + f32::from(self.speed.as_i16()) / Self::MPS_TO_INT_FACTOR } #[must_use] @@ -292,17 +316,18 @@ impl LongPositionVector { #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +// 20 byte in total pub struct ShortPositionVector { - pub gn_address: Address, + pub gn_address: Address, // 64 bits /// Expresses the time in milliseconds at which the latitude and longitude /// of the ITS-S were acquired by the GeoAdhoc router. The time is encoded as: /// TST = TST(TAI) % 2^32 /// where TST(TAI) is the number of elapsed TAI milliseconds since 2004-01-01 00:00:00.000 UTC - pub timestamp: Timestamp, + pub timestamp: Timestamp, // 32 bits /// WGS 84 [i.6] latitude of the GeoAdhoc router reference position expressed in 1/10 micro degree - pub latitude: i32, + pub latitude: i32, // 32 bits /// WGS 84 [i.6] longitude of the GeoAdhoc router reference position expressed in 1/10 micro degree - pub longitude: i32, + pub longitude: i32, // 32 bits } impl ShortPositionVector { @@ -336,20 +361,21 @@ impl ShortPositionVector { #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +// 4 byte in total pub struct BasicHeader { /// Identifies the version of the GeoNetworking protocol - pub version: u8, + pub version: u4, // 4 bits /// Identifies the type of header immediately following the GeoNetworking Basic Header - pub next_header: NextAfterBasic, + pub next_header: NextAfterBasic, // 4 bits (but only 2 LSB are used) /// Reserved. Set to 0 - pub reserved: Bits<8>, + pub reserved: u8, // 8 bits /// Lifetime field. Indicates the maximum tolerable time a packet may be buffered until it reaches its destination /// Bit 0 to Bit 5: LT sub-field Multiplier /// Bit 6 to Bit 7: LT sub-field Base - pub lifetime: Lifetime, + pub lifetime: Lifetime, // 8 bits /// Decremented by 1 by each GeoAdhoc router that forwards the packet /// The packet shall not be forwarded if RHL is decremented to zero - pub remaining_hop_limit: u8, + pub remaining_hop_limit: u8, // 8 bits } impl BasicHeader { @@ -364,17 +390,13 @@ impl BasicHeader { lifetime: Lifetime, remaining_hop_limit: u8, ) -> Result { - // version is 4 bit unsigned - if version > 15 { - return Err(Error::ValueOutOfBounds(OutOfBoundsError::new( - "version", "u4", - ))); - } + let version = u4::try_new(version) + .map_err(|_| Error::ValueOutOfBounds(OutOfBoundsError::new("version", "u4")))?; Ok(Self { version, next_header, - reserved: bits![0; 8], + reserved: 0, lifetime, remaining_hop_limit, }) @@ -390,6 +412,21 @@ pub enum NextAfterBasic { SecuredPacket = 2, } +impl TryFrom for NextAfterBasic { + type Error = alloc::string::String; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::Any), + 1 => Ok(Self::CommonHeader), + 2 => Ok(Self::SecuredPacket), + i => Err(alloc::format!( + "No corresponding header type for value {i}!" + )), + } + } +} + #[derive(Debug, Copy, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] /// Lifetime field. Indicates the maximum tolerable time a packet may be buffered until it reaches its destination @@ -471,24 +508,25 @@ impl Lifetime { #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +// 8 bytes in total pub struct CommonHeader { /// Identifies the type of header immediately following the GeoNetworking headers - pub next_header: NextAfterCommon, + pub next_header: NextAfterCommon, // 4 bits /// Reserved. Set to 0 - pub reserved_1: Bits<4>, + pub reserved_1: u4, // 4 bits /// Identifies the type and sub-type of the GeoNetworking header - pub header_type_and_subtype: HeaderType, + pub header_type_and_subtype: HeaderType, // 8 bits /// Traffic class that represents Facility-layer requirements on packet transport - pub traffic_class: TrafficClass, + pub traffic_class: TrafficClass, // 8 bits /// Bit 0: Indicates whether the ITS-S is mobile or stationary (GN protocol constant itsGnIsMobile) /// Bit 1 to Bit 7: Reserved, set to 0 - pub flags: Bits<8>, + pub flags: [bool; 8], // 8 bits /// Length of the GeoNetworking payload, i.e. the rest of the packet following the whole GeoNetworking header in octets, for example BTP + CAM - pub payload_length: u16, - /// The Maximum hop limit is not decremented by a GeoAdhoc router that forwards the packet - pub maximum_hop_limit: u8, + pub payload_length: u16, // 16 bits + /// The Maximum hop limit is not decremented by a GeoAdhoc router that forwards the packet + pub maximum_hop_limit: u8, // 8 bits /// Reserved. Set to 0 - pub reserved_2: Bits<8>, + pub reserved_2: u8, // 8 bits } impl CommonHeader { @@ -501,17 +539,15 @@ impl CommonHeader { payload_length: u16, maximum_hop_limit: u8, ) -> Self { - let flags = Bits(flags.iter().collect::<_>()); - Self { next_header, - reserved_1: bits![0; 4], + reserved_1: u4::from_u8(0), header_type_and_subtype, traffic_class, flags, payload_length, maximum_hop_limit, - reserved_2: bits![0; 8], + reserved_2: 0, } } @@ -525,18 +561,17 @@ impl CommonHeader { payload_length: u16, maximum_hop_limit: u8, ) -> Self { - let mobile_flag = u8::from(is_mobile); - let flags = bits![mobile_flag, 0, 0, 0, 0, 0, 0, 0]; + let flags = [is_mobile, false, false, false, false, false, false, false]; Self { next_header, - reserved_1: bits![0; 4], + reserved_1: u4::from_u8(0), header_type_and_subtype, traffic_class, flags, payload_length, maximum_hop_limit, - reserved_2: bits![0; 8], + reserved_2: 0, } } } @@ -551,7 +586,7 @@ pub struct TrafficClass { pub channel_offload: bool, /// Traffic class ID as specified in the media-dependent part of GeoNetworking corresponding to the interface /// over which the packet will be transmitted, e.g. in ETSI TS 102 636-4-2 [i.11] for ITS-G5 and ETSI TS 103 613 [i.10] for LTE-V2X - pub traffic_class_id: u8, + pub traffic_class_id: u6, // 6 bits } impl TrafficClass { @@ -565,13 +600,9 @@ impl TrafficClass { channel_offload: bool, traffic_class_id: u8, ) -> Result { - // traffic_class_id is 6 bit unsigned - if traffic_class_id > 63 { - return Err(Error::ValueOutOfBounds(OutOfBoundsError::new( - "traffic_class_id", - "u6", - ))); - } + let traffic_class_id = u6::try_new(traffic_class_id).map_err(|_| { + Error::ValueOutOfBounds(OutOfBoundsError::new("traffic_class_id", "u6")) + })?; Ok(Self { store_carry_forward, @@ -594,6 +625,22 @@ pub enum NextAfterCommon { IPv6 = 3, } +impl TryFrom for NextAfterCommon { + type Error = alloc::string::String; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::Any), + 1 => Ok(Self::BTPA), + 2 => Ok(Self::BTPB), + 3 => Ok(Self::IPv6), + i => Err(alloc::format!( + "No corresponding header type for value {i}!" + )), + } + } +} + #[derive(Debug, Copy, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] /// Identifies the type of the GeoNetworking header @@ -653,6 +700,56 @@ impl HeaderType { } } +impl TryFrom for HeaderType { + type Error = alloc::string::String; + + fn try_from(value: u8) -> Result { + // let (input, output) = + // nom::bits::bits::<_, _, nom::error::Error<(&[u8], usize)>, _, _>(|data| { + // let (data, foo) = nom::bits::streaming::take(4usize)(data)?; + // let (data, bar) = nom::bits::streaming::take(4usize)(data)?; + + // Ok((foo, bar)) + // })(vec![value])?; + + let ty = (value >> 4) & 0x0F; + let subtype = value & 0x0F; + + let error = alloc::format!( + "No corresponding header type for value {ty} and subtype value {subtype}!" + ); + + match ty { + 0 => Ok(Self::Any), + 1 => Ok(Self::Beacon), + 2 => Ok(Self::GeoUnicast), + 3 => match subtype { + 0 => Ok(Self::GeoAnycast(AreaType::Circular)), + 1 => Ok(Self::GeoAnycast(AreaType::Rectangular)), + 2 => Ok(Self::GeoAnycast(AreaType::Ellipsoidal)), + _ => Err(error), + }, + 4 => match subtype { + 0 => Ok(Self::GeoBroadcast(AreaType::Circular)), + 1 => Ok(Self::GeoBroadcast(AreaType::Rectangular)), + 2 => Ok(Self::GeoBroadcast(AreaType::Ellipsoidal)), + _ => Err(error), + }, + 5 => match subtype { + 0 => Ok(Self::TopologicallyScopedBroadcast(BroadcastType::SingleHop)), + 1 => Ok(Self::TopologicallyScopedBroadcast(BroadcastType::MultiHop)), + _ => Err(error), + }, + 6 => match subtype { + 0 => Ok(Self::LocationService(LocationServiceType::Request)), + 1 => Ok(Self::LocationService(LocationServiceType::Reply)), + _ => Err(error), + }, + _ => Err(error), + } + } +} + #[derive(Debug, Copy, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] /// Area type used in header subtypes @@ -680,6 +777,7 @@ pub enum LocationServiceType { #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +// different length depending on type pub enum ExtendedHeader { GUC(GeoUnicast), TSB(TopologicallyScopedBroadcast), @@ -693,15 +791,16 @@ pub enum ExtendedHeader { #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +// 48 byte in total pub struct GeoUnicast { /// Sequence number field. Indicates the index of the sent GUC packet (clause 8.3) and used to detect duplicate GeoNetworking packets - pub sequence_number: u16, + pub sequence_number: u16, // 16 bits /// Reserved. Set to 0 - pub reserved: Bits<16>, + pub reserved: u16, // 16 bits /// Long Position Vector containing the reference position of the source - pub source_position_vector: LongPositionVector, + pub source_position_vector: LongPositionVector, // 192 bits (24 byte) /// Short Position Vector containing the position of the destination - pub destination_position_vector: ShortPositionVector, + pub destination_position_vector: ShortPositionVector, // 160 bits (20 byte) } impl GeoUnicast { @@ -713,7 +812,7 @@ impl GeoUnicast { ) -> Self { Self { sequence_number, - reserved: bits![0; 16], + reserved: 0, source_position_vector, destination_position_vector, } @@ -722,13 +821,14 @@ impl GeoUnicast { #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +// 28 byte in total pub struct TopologicallyScopedBroadcast { /// Sequence number field. Indicates the index of the sent TSB packet (clause 8.3) and used to detect duplicate GeoNetworking packets - pub sequence_number: u16, + pub sequence_number: u16, // 16 bits /// Reserved. Set to 0 - pub reserved: Bits<16>, + pub reserved: u16, // 16 bits /// Long Position Vector containing the reference position of the source - pub source_position_vector: LongPositionVector, + pub source_position_vector: LongPositionVector, // 192 bits (24 byte) } impl TopologicallyScopedBroadcast { @@ -736,7 +836,7 @@ impl TopologicallyScopedBroadcast { pub fn new(sequence_number: u16, source_position_vector: LongPositionVector) -> Self { Self { sequence_number, - reserved: bits![0; 16], + reserved: 0, source_position_vector, } } @@ -744,11 +844,12 @@ impl TopologicallyScopedBroadcast { #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +// 28 byte in total pub struct SingleHopBroadcast { /// Long Position Vector containing the reference position of the source - pub source_position_vector: LongPositionVector, + pub source_position_vector: LongPositionVector, // 192 bits (24 byte) /// Used for media-dependent operations. If not used, it shall be set to 0 - pub media_dependent_data: [u8; 4], + pub media_dependent_data: [u8; 4], // 32 bits } pub type GeoBroadcast = GeoAnycast; @@ -759,25 +860,26 @@ pub type GeoBroadcast = GeoAnycast; /// 1) Distance a is set to the radius r. /// 2) Distance b is set to 0. /// 3) Angle is set to 0. +// 44 byte in total pub struct GeoAnycast { /// Sequence number field. Indicates the index of the sent GBC/GAC packet (clause 8.3) and used to detect duplicate GeoNetworking packets - pub sequence_number: u16, + pub sequence_number: u16, // 16 bits /// Reserved. Set to 0 - pub reserved_1: Bits<16>, + pub reserved_1: u16, // 16 bits /// Long Position Vector containing the reference position of the source - pub source_position_vector: LongPositionVector, + pub source_position_vector: LongPositionVector, // 192 bits (24 byte) /// WGS 84 [i.6] latitude for the centre position of the geometric shape as defined in ETSI EN 302 931 \[8\] in 1/10 micro degree - pub geo_area_position_latitude: i32, + pub geo_area_position_latitude: i32, // 32 bits /// WGS 84 [i.6] longitude for the centre position of the geometric shape as defined in ETSI EN 302 931 \[8\] in 1/10 micro degree - pub geo_area_position_longitude: i32, + pub geo_area_position_longitude: i32, // 32 bits /// Distance a of the geometric shape as defined in ETSI EN 302 931 \[8\] in meters - pub distance_a: u16, + pub distance_a: u16, // 16 bits /// Distance b of the geometric shape as defined in ETSI EN 302 931 \[8\] in meters - pub distance_b: u16, + pub distance_b: u16, // 16 bits /// Angle of the geometric shape as defined in ETSI EN 302 931 \[8\] in degrees from North - pub angle: u16, + pub angle: u16, // 16 bits /// Reserved. Set to 0 - pub reserved_2: Bits<16>, + pub reserved_2: u16, // 16 bits } impl GeoAnycast { @@ -829,36 +931,38 @@ impl GeoAnycast { ) -> Self { Self { sequence_number, - reserved_1: bits![0; 16], + reserved_1: 0, source_position_vector, geo_area_position_latitude, geo_area_position_longitude, distance_a, distance_b, angle, - reserved_2: bits![0; 16], + reserved_2: 0, } } } #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +// 24 byte in total pub struct Beacon { /// Long Position Vector containing the reference position of the source - pub source_position_vector: LongPositionVector, + pub source_position_vector: LongPositionVector, // 192 bits (24 byte) } #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +// 36 byte in total pub struct LSRequest { /// Sequence number field. Indicates the index of the sent LS Request packet (clause 8.3) and used to detect duplicate GeoNetworking packets - pub sequence_number: u16, + pub sequence_number: u16, // 16 bits /// Reserved. Set to 0 - pub reserved: Bits<16>, + pub reserved: u16, // 16 bits /// Long Position Vector containing the reference position of the source - pub source_position_vector: LongPositionVector, + pub source_position_vector: LongPositionVector, // 192 bits (24 byte) /// The `GN_ADDR` address for the GeoAdhoc router entity for which the location is being requested - pub request_gn_address: Address, + pub request_gn_address: Address, // 64 bits } impl LSRequest { @@ -870,7 +974,7 @@ impl LSRequest { ) -> Self { Self { sequence_number, - reserved: bits![0; 16], + reserved: 0, source_position_vector, request_gn_address, } @@ -879,15 +983,16 @@ impl LSRequest { #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +// 48 byte in total pub struct LSReply { /// Sequence number field. Indicates the index of the sent LS Reply packet (clause 8.3) and used to detect duplicate GeoNetworking packets - pub sequence_number: u16, + pub sequence_number: u16, // 16 bits /// Reserved. Set to 0 - pub reserved: Bits<16>, + pub reserved: u16, // 16 bits /// Long Position Vector containing the reference position of the source, which represents the Request `GN_ADDR` in the corresponding LS Request - pub source_position_vector: LongPositionVector, + pub source_position_vector: LongPositionVector, // 192 bits (24 byte) /// Short Position Vector containing the position of the destination - pub destination_position_vector: ShortPositionVector, + pub destination_position_vector: ShortPositionVector, // 160 bits (20 byte) } impl LSReply { @@ -899,7 +1004,7 @@ impl LSReply { ) -> Self { Self { sequence_number, - reserved: bits![0; 16], + reserved: 0, source_position_vector, destination_position_vector, } diff --git a/src/standards/ieee1609dot2.rs b/src/standards/ieee1609dot2.rs index 99ee017..166a305 100644 --- a/src/standards/ieee1609dot2.rs +++ b/src/standards/ieee1609dot2.rs @@ -6,8 +6,6 @@ use { core::fmt::Debug, }; -use crate::Bits; - #[cfg(feature = "json")] use serde::Serialize; @@ -319,9 +317,37 @@ pub enum EncryptedDataEncryptionKey<'input> { /// end-entity certificate may contain an appPermissions field. If enroll is /// indicated, the end-entity certificate may contain a certRequestPermissions /// field. +/// +/// ASN.1 Definition: `BIT STRING {app (0), enrol (1) } (SIZE (8)) (ALL EXCEPT {})` #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize))] -pub struct EndEntityType(pub Bits<8>); +pub struct EndEntityType(pub BitString<8>); + +impl From> for EndEntityType { + fn from(value: Vec) -> Self { + Self(value.into()) + } +} + +impl From<[bool; 8]> for EndEntityType { + fn from(value: [bool; 8]) -> Self { + Self(value.into()) + } +} + +impl EndEntityType { + // bit 0 + #[must_use] + pub fn has_app(&self) -> bool { + self.0 .0[0] + } + + // bit 1 + #[must_use] + pub fn has_enrol(&self) -> bool { + self.0 .0[1] + } +} /// Profile of the `CertificateBase` structure providing all the fields necessary for an explicit certificate, and no others pub type ExplicitCertificate<'input> = CertificateBase<'input>; @@ -1216,7 +1242,9 @@ pub struct ToBeSignedCertificate<'input> { /// consistency checks on received certificate responses. No functionality /// associated with communications between peer SDEEs is defined associated /// with this field. - pub flags: Option>, + /// + /// ASN.1 Definition: BIT STRING {usesCubk (0)} (SIZE (8)) OPTIONAL, + pub flags: Option>, /// indicates additional permissions that may be applied to application activities that the certificate holder is carrying out #[cfg_attr(feature = "serde", serde(borrow))] @@ -2595,16 +2623,6 @@ pub struct ThreeDLocation { pub elevation: Elevation, } -//************************************************************************** -// Time Structures -//************************************************************************** - -/// The number of (TAI) seconds since 00:00:00 UTC, 1 January, 2004 -pub type Time32 = Uint32; - -/// Estimate of the number of (TAI) microseconds since 00:00:00 UTC, 1 January, 2004 -pub type Time64 = Uint64; - /// is used to define validity regions for use in certificates /// /// The latitude and longitude fields contain the latitude and @@ -2622,17 +2640,38 @@ pub struct TwoDLocation { pub longitude: Longitude, } -/// This atomic type is used in the definition of other data structures +//************************************************************************** +// Time Structures +//************************************************************************** + +/// The number of (TAI) seconds since 00:00:00 UTC, 1 January, 2004 +pub type Time32 = Uint32; + +/// Estimate of the number of (TAI) microseconds since 00:00:00 UTC, 1 January, 2004 +pub type Time64 = Uint64; + +/// gives the validity period of a certificate /// -/// It is for non-negative integers up to 65,535, i.e., (hex)ff ff. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +/// The start of the validity period is given by start and the end is given by +/// start + duration. +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize))] -pub struct Uint16(pub u16); +pub struct ValidityPeriod { + pub start: Time32, + pub duration: Duration, +} //************************************************************************** // Integer Types //************************************************************************** +/// This atomic type is used in the definition of other data structures +/// +/// It is for non-negative integers up to 65,535, i.e., (hex)ff ff. +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize))] +pub struct Uint16(pub u16); + /// This atomic type is used in the definition of other data structures /// /// It is for non-negative integers up to 7, i.e., (hex)07. @@ -2708,13 +2747,56 @@ pub struct UnknownLatitude(pub NinetyDegreeInt); #[cfg_attr(feature = "serde", derive(Serialize))] pub struct UnknownLongitude(pub OneEightyDegreeInt); -/// gives the validity period of a certificate -/// -/// The start of the validity period is given by start and the end is given by -/// start + duration. +//************************************************************************** +// Bit Field Types +//************************************************************************** + +/// Fixed size, non-extensible BIT STRING #[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "serde", derive(Serialize))] -pub struct ValidityPeriod { - pub start: Time32, - pub duration: Duration, +pub struct BitString(pub [bool; SIZE]); + +impl Default for BitString { + fn default() -> Self { + Self([false; SIZE]) + } } + +#[cfg(feature = "serde")] +impl Serialize for BitString { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeTuple; + let mut seq = serializer.serialize_tuple(self.0.len())?; + for elem in &self.0 { + use serde::ser::SerializeTuple; + + seq.serialize_element(elem)?; + } + seq.end() + } +} + +impl From> for BitString { + fn from(value: Vec) -> Self { + let mut res = Self::default(); + let input_size = value.len(); + + for (idx, item) in value.iter().enumerate().take(SIZE.min(input_size)) { + res.0[idx] = *item; + } + + res + } +} + +impl From<[bool; SIZE]> for BitString { + fn from(value: [bool; SIZE]) -> Self { + Self(value) + } +} + +//************************************************************************** +// Tests +//************************************************************************** diff --git a/src/util.rs b/src/util.rs index a72ba6e..fa012d6 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,28 +1,7 @@ extern crate alloc; -use bitvec::prelude::*; -use nom_bitvec::BSlice; - use crate::DecodeError; -pub(crate) fn write_into_vec_left_padded( - bits: BSlice<'_, u8, Msb0>, - vec: &mut alloc::vec::Vec, -) { - let missing_bits = 8 - bits.len() % 8; - if missing_bits == 8 { - for slice in bits.chunks(8) { - vec.push(slice.load_be()); - } - } else { - let mut padding = bitvec![u8, bitvec::prelude::Msb0; 0; missing_bits]; - padding.append(&mut bits.to_bitvec()); - for s in padding.chunks(8) { - vec.push(s.load_be()); - } - } -} - pub(crate) fn cast_nom_err(error: nom::Err>) -> nom::Err> where DecodeError: Into>, @@ -33,3 +12,20 @@ where nom::Err::Failure(e) => nom::Err::Failure(e.into()), } } + +/// Calculates number of padding bits when writing bits to an octet buffer +pub(crate) fn bitstring_padding_bits(len: usize) -> usize { + let extra_bits = len % 8; + + // 0 extra bits mean no padding needed + if extra_bits > 0 { + 8 - extra_bits + } else { + 0 + } +} + +/// Calculates required number octets for a certain bit vector length +pub(crate) fn bitstring_buffer_size(len: usize) -> usize { + num::Integer::div_ceil(&len, &8usize) +} diff --git a/tests/lib_test.rs b/tests/lib_test.rs index 681b8ec..b5388ef 100644 --- a/tests/lib_test.rs +++ b/tests/lib_test.rs @@ -1,3 +1,4 @@ +use arbitrary_int::{u10, u4}; use geonetworking::*; #[test] @@ -13,42 +14,39 @@ fn decode_beacon() { Decoded { bytes_consumed: 36, decoded: Packet::Unsecured { - basic: en302636_4_1::BasicHeader { - version: 1, - next_header: en302636_4_1::NextAfterBasic::CommonHeader, - reserved: bits![0, 0, 0, 0, 0, 0, 0, 0], - lifetime: en302636_4_1::Lifetime(26), - remaining_hop_limit: 1 - }, + basic: en302636_4_1::BasicHeader::try_new( + 1, + en302636_4_1::NextAfterBasic::CommonHeader, + en302636_4_1::Lifetime(26), + 1 + ) + .unwrap(), common: en302636_4_1::CommonHeader { next_header: en302636_4_1::NextAfterCommon::Any, - reserved_1: bits![0, 0, 0, 0], + reserved_1: u4::from_u8(0x00), header_type_and_subtype: en302636_4_1::HeaderType::Beacon, - traffic_class: en302636_4_1::TrafficClass { - store_carry_forward: false, - channel_offload: false, - traffic_class_id: 3 - }, - flags: bits![0, 0, 0, 0, 0, 0, 0, 0], + traffic_class: en302636_4_1::TrafficClass::try_new(false, false, 3).unwrap(), + flags: [false; 8], payload_length: 0, maximum_hop_limit: 1, - reserved_2: bits![0, 0, 0, 0, 0, 0, 0, 0] + reserved_2: 0x00 }, extended: Some(en302636_4_1::ExtendedHeader::Beacon(en302636_4_1::Beacon { - source_position_vector: en302636_4_1::LongPositionVector { - gn_address: en302636_4_1::Address { + source_position_vector: en302636_4_1::LongPositionVector::try_new( + en302636_4_1::Address { manually_configured: false, station_type: en302636_4_1::StationType::RoadSideUnit, - reserved: bits![0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + reserved: u10::new(0x0000), address: [0, 13, 65, 18, 54, 112] }, - timestamp: en302636_4_1::Timestamp(1_897_856_500), - latitude: 535_637_062, - longitude: 99_895_661, - position_accuracy: true, - speed: 0, - heading: 3407 - } + en302636_4_1::Timestamp(1_897_856_500), + 535_637_062, + 99_895_661, + true, + 0, + 3407 + ) + .unwrap(), })), payload: &[] }, @@ -76,45 +74,42 @@ fn unsecured_round_trip() { 0x4d, 0x90, 0x02, 0xa8, 0x08, 0x4a, 0x7f, 0x00, 0xb8, 0x00, 0x00, ]; let packet = Packet::Unsecured { - basic: en302636_4_1::BasicHeader { - version: 1, - next_header: en302636_4_1::NextAfterBasic::CommonHeader, - reserved: bits![0, 0, 0, 0, 0, 0, 0, 0], - lifetime: en302636_4_1::Lifetime(80), - remaining_hop_limit: 1, - }, + basic: en302636_4_1::BasicHeader::try_new( + 1, + en302636_4_1::NextAfterBasic::CommonHeader, + en302636_4_1::Lifetime(80), + 1, + ) + .unwrap(), common: en302636_4_1::CommonHeader { next_header: en302636_4_1::NextAfterCommon::BTPB, - reserved_1: bits![0, 0, 0, 0], + reserved_1: u4::from_u8(0x00), header_type_and_subtype: en302636_4_1::HeaderType::TopologicallyScopedBroadcast( en302636_4_1::BroadcastType::SingleHop, ), - traffic_class: en302636_4_1::TrafficClass { - store_carry_forward: false, - channel_offload: false, - traffic_class_id: 2, - }, - flags: bits![0, 0, 0, 0, 0, 0, 0, 0], + traffic_class: en302636_4_1::TrafficClass::try_new(false, false, 2).unwrap(), + flags: [false; 8], payload_length: 1, maximum_hop_limit: 1, - reserved_2: bits![0, 0, 0, 0, 0, 0, 0, 0], + reserved_2: 0x00, }, extended: Some(en302636_4_1::ExtendedHeader::SHB( en302636_4_1::SingleHopBroadcast { - source_position_vector: en302636_4_1::LongPositionVector { - gn_address: en302636_4_1::Address { + source_position_vector: en302636_4_1::LongPositionVector::try_new( + en302636_4_1::Address { manually_configured: false, station_type: en302636_4_1::StationType::Unknown, - reserved: bits![0, 1, 0, 0, 0, 0, 0, 1, 1, 0], + reserved: u10::new(0x0106), address: [0, 96, 224, 105, 87, 141], }, - timestamp: en302636_4_1::Timestamp(542_947_520), - latitude: 535_574_568, - longitude: 99_765_648, - position_accuracy: false, - speed: 680, - heading: 2122, - }, + en302636_4_1::Timestamp(542_947_520), + 535_574_568, + 99_765_648, + false, + 680, + 2122, + ) + .unwrap(), media_dependent_data: [127, 0, 184, 0], }, )), @@ -141,7 +136,7 @@ fn packet_to_json() { let result = Packet::decode(data.as_slice()).unwrap(); let json = result.decoded.encode_to_json().unwrap(); pretty_assertions::assert_eq!( - serde_json::from_str::(r#"{"Unsecured":{"basic":{"version":1,"next_header":"CommonHeader","reserved":[false,false,false,false,false,false,false,false],"lifetime":80,"remaining_hop_limit":1},"common":{"next_header":"BTPB","reserved_1":[false,false,false,false],"header_type_and_subtype":{"TopologicallyScopedBroadcast":"SingleHop"},"traffic_class":{"store_carry_forward":false,"channel_offload":false,"traffic_class_id":2},"flags":[false,false,false,false,false,false,false,false],"payload_length":45,"maximum_hop_limit":1,"reserved_2":[false,false,false,false,false,false,false,false]},"extended":{"SHB":{"source_position_vector":{"gn_address":{"manually_configured":false,"station_type":"Unknown","reserved":[false,true,false,false,false,false,false,true,true,false],"address":[0,96,224,105,87,141]},"timestamp":542947520,"latitude":535574568,"longitude":99765648,"position_accuracy":false,"speed":680,"heading":2122},"media_dependent_data":[127,0,184,0]}},"payload":[7,209,0,0,2,2,224,105,87,141,180,217,0,10,178,36,99,206,39,132,43,31,255,255,252,34,49,181,178,0,128,95,65,45,162,191,233,237,7,55,254,235,255,246,0]}}"#).unwrap(), + serde_json::from_str::(r#"{"Unsecured":{"basic":{"version":1,"next_header":"CommonHeader","reserved":0,"lifetime":80,"remaining_hop_limit":1},"common":{"next_header":"BTPB","reserved_1":0,"header_type_and_subtype":{"TopologicallyScopedBroadcast":"SingleHop"},"traffic_class":{"store_carry_forward":false,"channel_offload":false,"traffic_class_id":2},"flags":[false,false,false,false,false,false,false,false],"payload_length":45,"maximum_hop_limit":1,"reserved_2":0},"extended":{"SHB":{"source_position_vector":{"gn_address":{"manually_configured":false,"station_type":"Unknown","reserved":262,"address":[0,96,224,105,87,141]},"timestamp":542947520,"latitude":535574568,"longitude":99765648,"position_accuracy":false,"speed":680,"heading":2122},"media_dependent_data":[127,0,184,0]}},"payload":[7,209,0,0,2,2,224,105,87,141,180,217,0,10,178,36,99,206,39,132,43,31,255,255,252,34,49,181,178,0,128,95,65,45,162,191,233,237,7,55,254,235,255,246,0]}}"#).unwrap(), serde_json::from_str::(json.as_str()).unwrap() ); }