-
Notifications
You must be signed in to change notification settings - Fork 443
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #827 from thvdveld/ipv6-hop-by-hop
refactor: move IPv6 HBH in own module
- Loading branch information
Showing
8 changed files
with
200 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
use super::{Error, Ipv6Option, Ipv6OptionRepr, Ipv6OptionsIterator, Result}; | ||
|
||
use heapless::Vec; | ||
|
||
/// A read/write wrapper around an IPv6 Hop-by-Hop Header buffer. | ||
pub struct Header<T: AsRef<[u8]>> { | ||
buffer: T, | ||
} | ||
|
||
impl<T: AsRef<[u8]>> Header<T> { | ||
/// Create a raw octet buffer with an IPv6 Hop-by-Hop Header structure. | ||
pub const fn new_unchecked(buffer: T) -> Self { | ||
Header { buffer } | ||
} | ||
|
||
/// Shorthand for a combination of [new_unchecked] and [check_len]. | ||
/// | ||
/// [new_unchecked]: #method.new_unchecked | ||
/// [check_len]: #method.check_len | ||
pub fn new_checked(buffer: T) -> Result<Self> { | ||
let header = Self::new_unchecked(buffer); | ||
header.check_len()?; | ||
Ok(header) | ||
} | ||
|
||
/// Ensure that no accessor method will panic if called. | ||
/// Returns `Err(Error)` if the buffer is too short. | ||
/// | ||
/// The result of this check is invalidated by calling [set_header_len]. | ||
/// | ||
/// [set_header_len]: #method.set_header_len | ||
pub fn check_len(&self) -> Result<()> { | ||
if self.buffer.as_ref().is_empty() { | ||
return Err(Error); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Consume the header, returning the underlying buffer. | ||
pub fn into_inner(self) -> T { | ||
self.buffer | ||
} | ||
} | ||
|
||
impl<'a, T: AsRef<[u8]> + ?Sized> Header<&'a T> { | ||
/// Return the options of the IPv6 Hop-by-Hop header. | ||
pub fn options(&self) -> &'a [u8] { | ||
self.buffer.as_ref() | ||
} | ||
} | ||
|
||
impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Header<&'a mut T> { | ||
/// Return a mutable pointer to the options of the IPv6 Hop-by-Hop header. | ||
pub fn options_mut(&mut self) -> &mut [u8] { | ||
self.buffer.as_mut() | ||
} | ||
} | ||
|
||
/// A high-level representation of an IPv6 Hop-by-Hop Header. | ||
#[derive(Debug, PartialEq, Eq, Clone)] | ||
#[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
pub struct Repr<'a> { | ||
pub options: heapless::Vec<Ipv6OptionRepr<'a>, { crate::config::IPV6_HBH_MAX_OPTIONS }>, | ||
} | ||
|
||
impl<'a> Repr<'a> { | ||
/// Parse an IPv6 Hop-by-Hop Header and return a high-level representation. | ||
pub fn parse<T>(header: &'a Header<&'a T>) -> Result<Repr<'a>> | ||
where | ||
T: AsRef<[u8]> + ?Sized, | ||
{ | ||
let mut options = Vec::new(); | ||
|
||
let iter = Ipv6OptionsIterator::new(header.options()); | ||
|
||
for option in iter { | ||
let option = option?; | ||
|
||
if let Err(e) = options.push(option) { | ||
net_trace!("eror when parsing hop-by-hop options: {}", e); | ||
break; | ||
} | ||
} | ||
|
||
Ok(Self { options }) | ||
} | ||
|
||
/// Return the length, in bytes, of a header that will be emitted from this high-level | ||
/// representation. | ||
pub fn buffer_len(&self) -> usize { | ||
self.options.iter().map(|o| o.buffer_len()).sum() | ||
} | ||
|
||
/// Emit a high-level representation into an IPv6 Hop-by-Hop Header. | ||
pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>) { | ||
let mut buffer = header.options_mut(); | ||
|
||
for opt in &self.options { | ||
opt.emit(&mut Ipv6Option::new_unchecked( | ||
&mut buffer[..opt.buffer_len()], | ||
)); | ||
buffer = &mut buffer[opt.buffer_len()..]; | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use crate::wire::Error; | ||
|
||
// A Hop-by-Hop Option header with a PadN option of option data length 4. | ||
static REPR_PACKET_PAD4: [u8; 6] = [0x1, 0x4, 0x0, 0x0, 0x0, 0x0]; | ||
|
||
// A Hop-by-Hop Option header with a PadN option of option data length 12. | ||
static REPR_PACKET_PAD12: [u8; 14] = [ | ||
0x1, 0x0C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||
]; | ||
|
||
#[test] | ||
fn test_check_len() { | ||
// zero byte buffer | ||
assert_eq!( | ||
Err(Error), | ||
Header::new_unchecked(&REPR_PACKET_PAD4[..0]).check_len() | ||
); | ||
// valid | ||
assert_eq!(Ok(()), Header::new_unchecked(&REPR_PACKET_PAD4).check_len()); | ||
// valid | ||
assert_eq!( | ||
Ok(()), | ||
Header::new_unchecked(&REPR_PACKET_PAD12).check_len() | ||
); | ||
} | ||
|
||
#[test] | ||
fn test_repr_parse_valid() { | ||
let header = Header::new_unchecked(&REPR_PACKET_PAD4); | ||
let repr = Repr::parse(&header).unwrap(); | ||
|
||
let mut options = Vec::new(); | ||
options.push(Ipv6OptionRepr::PadN(4)).unwrap(); | ||
assert_eq!(repr, Repr { options }); | ||
|
||
let header = Header::new_unchecked(&REPR_PACKET_PAD12); | ||
let repr = Repr::parse(&header).unwrap(); | ||
|
||
let mut options = Vec::new(); | ||
options.push(Ipv6OptionRepr::PadN(12)).unwrap(); | ||
assert_eq!(repr, Repr { options }); | ||
} | ||
|
||
#[test] | ||
fn test_repr_emit() { | ||
let mut options = Vec::new(); | ||
options.push(Ipv6OptionRepr::PadN(4)).unwrap(); | ||
let repr = Repr { options }; | ||
|
||
let mut bytes = [0u8; 6]; | ||
let mut header = Header::new_unchecked(&mut bytes); | ||
repr.emit(&mut header); | ||
|
||
assert_eq!(header.into_inner(), &REPR_PACKET_PAD4[..]); | ||
|
||
let mut options = Vec::new(); | ||
options.push(Ipv6OptionRepr::PadN(12)).unwrap(); | ||
let repr = Repr { options }; | ||
|
||
let mut bytes = [0u8; 14]; | ||
let mut header = Header::new_unchecked(&mut bytes); | ||
repr.emit(&mut header); | ||
|
||
assert_eq!(header.into_inner(), &REPR_PACKET_PAD12[..]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters