ipv6hbh.rs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. use super::{Error, Ipv6Option, Ipv6OptionRepr, Ipv6OptionsIterator, Result};
  2. use crate::config;
  3. use crate::wire::ipv6option::RouterAlert;
  4. use heapless::Vec;
  5. /// A read/write wrapper around an IPv6 Hop-by-Hop Header buffer.
  6. pub struct Header<T: AsRef<[u8]>> {
  7. buffer: T,
  8. }
  9. impl<T: AsRef<[u8]>> Header<T> {
  10. /// Create a raw octet buffer with an IPv6 Hop-by-Hop Header structure.
  11. pub const fn new_unchecked(buffer: T) -> Self {
  12. Header { buffer }
  13. }
  14. /// Shorthand for a combination of [new_unchecked] and [check_len].
  15. ///
  16. /// [new_unchecked]: #method.new_unchecked
  17. /// [check_len]: #method.check_len
  18. pub fn new_checked(buffer: T) -> Result<Self> {
  19. let header = Self::new_unchecked(buffer);
  20. header.check_len()?;
  21. Ok(header)
  22. }
  23. /// Ensure that no accessor method will panic if called.
  24. /// Returns `Err(Error)` if the buffer is too short.
  25. ///
  26. /// The result of this check is invalidated by calling [set_header_len].
  27. ///
  28. /// [set_header_len]: #method.set_header_len
  29. pub fn check_len(&self) -> Result<()> {
  30. if self.buffer.as_ref().is_empty() {
  31. return Err(Error);
  32. }
  33. Ok(())
  34. }
  35. /// Consume the header, returning the underlying buffer.
  36. pub fn into_inner(self) -> T {
  37. self.buffer
  38. }
  39. }
  40. impl<'a, T: AsRef<[u8]> + ?Sized> Header<&'a T> {
  41. /// Return the options of the IPv6 Hop-by-Hop header.
  42. pub fn options(&self) -> &'a [u8] {
  43. self.buffer.as_ref()
  44. }
  45. }
  46. impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Header<&'a mut T> {
  47. /// Return a mutable pointer to the options of the IPv6 Hop-by-Hop header.
  48. pub fn options_mut(&mut self) -> &mut [u8] {
  49. self.buffer.as_mut()
  50. }
  51. }
  52. /// A high-level representation of an IPv6 Hop-by-Hop Header.
  53. #[derive(Debug, PartialEq, Eq, Clone)]
  54. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  55. pub struct Repr<'a> {
  56. pub options: Vec<Ipv6OptionRepr<'a>, { config::IPV6_HBH_MAX_OPTIONS }>,
  57. }
  58. impl<'a> Repr<'a> {
  59. /// Parse an IPv6 Hop-by-Hop Header and return a high-level representation.
  60. pub fn parse<T>(header: &'a Header<&'a T>) -> Result<Repr<'a>>
  61. where
  62. T: AsRef<[u8]> + ?Sized,
  63. {
  64. header.check_len()?;
  65. let mut options = Vec::new();
  66. let iter = Ipv6OptionsIterator::new(header.options());
  67. for option in iter {
  68. let option = option?;
  69. if let Err(e) = options.push(option) {
  70. net_trace!("error when parsing hop-by-hop options: {}", e);
  71. break;
  72. }
  73. }
  74. Ok(Self { options })
  75. }
  76. /// Return the length, in bytes, of a header that will be emitted from this high-level
  77. /// representation.
  78. pub fn buffer_len(&self) -> usize {
  79. self.options.iter().map(|o| o.buffer_len()).sum()
  80. }
  81. /// Emit a high-level representation into an IPv6 Hop-by-Hop Header.
  82. pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>) {
  83. let mut buffer = header.options_mut();
  84. for opt in &self.options {
  85. opt.emit(&mut Ipv6Option::new_unchecked(
  86. &mut buffer[..opt.buffer_len()],
  87. ));
  88. buffer = &mut buffer[opt.buffer_len()..];
  89. }
  90. }
  91. /// The hop-by-hop header containing a MLDv2 router alert option
  92. pub fn mldv2_router_alert() -> Self {
  93. let mut options = Vec::new();
  94. options
  95. .push(Ipv6OptionRepr::RouterAlert(
  96. RouterAlert::MulticastListenerDiscovery,
  97. ))
  98. .unwrap();
  99. Self { options }
  100. }
  101. /// Append a PadN option to the vector of hop-by-hop options
  102. pub fn push_padn_option(&mut self, n: u8) {
  103. self.options.push(Ipv6OptionRepr::PadN(n)).unwrap();
  104. }
  105. }
  106. #[cfg(test)]
  107. mod tests {
  108. use super::*;
  109. use crate::wire::Error;
  110. // A Hop-by-Hop Option header with a PadN option of option data length 4.
  111. static REPR_PACKET_PAD4: [u8; 6] = [0x1, 0x4, 0x0, 0x0, 0x0, 0x0];
  112. // A Hop-by-Hop Option header with a PadN option of option data length 12.
  113. static REPR_PACKET_PAD12: [u8; 14] = [
  114. 0x1, 0x0C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  115. ];
  116. #[test]
  117. fn test_check_len() {
  118. // zero byte buffer
  119. assert_eq!(
  120. Err(Error),
  121. Header::new_unchecked(&REPR_PACKET_PAD4[..0]).check_len()
  122. );
  123. // valid
  124. assert_eq!(Ok(()), Header::new_unchecked(&REPR_PACKET_PAD4).check_len());
  125. // valid
  126. assert_eq!(
  127. Ok(()),
  128. Header::new_unchecked(&REPR_PACKET_PAD12).check_len()
  129. );
  130. }
  131. #[test]
  132. fn test_repr_parse_valid() {
  133. let header = Header::new_unchecked(&REPR_PACKET_PAD4);
  134. let repr = Repr::parse(&header).unwrap();
  135. let mut options = Vec::new();
  136. options.push(Ipv6OptionRepr::PadN(4)).unwrap();
  137. assert_eq!(repr, Repr { options });
  138. let header = Header::new_unchecked(&REPR_PACKET_PAD12);
  139. let repr = Repr::parse(&header).unwrap();
  140. let mut options = Vec::new();
  141. options.push(Ipv6OptionRepr::PadN(12)).unwrap();
  142. assert_eq!(repr, Repr { options });
  143. }
  144. #[test]
  145. fn test_repr_emit() {
  146. let mut options = Vec::new();
  147. options.push(Ipv6OptionRepr::PadN(4)).unwrap();
  148. let repr = Repr { options };
  149. let mut bytes = [0u8; 6];
  150. let mut header = Header::new_unchecked(&mut bytes);
  151. repr.emit(&mut header);
  152. assert_eq!(header.into_inner(), &REPR_PACKET_PAD4[..]);
  153. let mut options = Vec::new();
  154. options.push(Ipv6OptionRepr::PadN(12)).unwrap();
  155. let repr = Repr { options };
  156. let mut bytes = [0u8; 14];
  157. let mut header = Header::new_unchecked(&mut bytes);
  158. repr.emit(&mut header);
  159. assert_eq!(header.into_inner(), &REPR_PACKET_PAD12[..]);
  160. }
  161. }