소스 검색

Rewrite IPv6 extension headers

Thibaut Vandervelden 1 년 전
부모
커밋
4ea83546df
7개의 변경된 파일179개의 추가작업 그리고 345개의 파일을 삭제
  1. 6 4
      src/iface/interface/ipv6.rs
  2. 2 2
      src/iface/interface/tests.rs
  3. 62 128
      src/wire/ipv6ext_header.rs
  4. 21 48
      src/wire/ipv6fragment.rs
  5. 3 17
      src/wire/ipv6option.rs
  6. 74 142
      src/wire/ipv6routing.rs
  7. 11 4
      src/wire/mod.rs

+ 6 - 4
src/iface/interface/ipv6.rs

@@ -244,9 +244,11 @@ impl InterfaceInner {
         handled_by_raw_socket: bool,
         ip_payload: &'frame [u8],
     ) -> Option<IpPacket<'frame>> {
-        let hbh_pkt = check!(Ipv6HopByHopHeader::new_checked(ip_payload));
-        let hbh_repr = check!(Ipv6HopByHopRepr::parse(&hbh_pkt));
-        for opt_repr in hbh_repr.options() {
+        let hbh_hdr = check!(Ipv6HopByHopHeader::new_checked(ip_payload));
+        let hbh_repr = check!(Ipv6HopByHopRepr::parse(&hbh_hdr));
+
+        let hbh_options = Ipv6OptionsIterator::new(hbh_repr.data);
+        for opt_repr in hbh_options {
             let opt_repr = check!(opt_repr);
             match opt_repr {
                 Ipv6OptionRepr::Pad1 | Ipv6OptionRepr::PadN(_) => (),
@@ -273,7 +275,7 @@ impl InterfaceInner {
             ipv6_repr,
             hbh_repr.next_header,
             handled_by_raw_socket,
-            &ip_payload[hbh_repr.buffer_len()..],
+            &ip_payload[hbh_repr.header_len() + hbh_repr.data.len()..],
         )
     }
 

+ 2 - 2
src/iface/interface/tests.rs

@@ -1063,11 +1063,11 @@ fn test_icmpv6_nxthdr_unknown() {
             hbh_pkt.set_header_len(0);
             offset += 8;
             {
-                let mut pad_pkt = Ipv6Option::new_unchecked(&mut *hbh_pkt.options_mut());
+                let mut pad_pkt = Ipv6Option::new_unchecked(&mut hbh_pkt.payload_mut()[..]);
                 Ipv6OptionRepr::PadN(3).emit(&mut pad_pkt);
             }
             {
-                let mut pad_pkt = Ipv6Option::new_unchecked(&mut hbh_pkt.options_mut()[5..]);
+                let mut pad_pkt = Ipv6Option::new_unchecked(&mut hbh_pkt.payload_mut()[5..]);
                 Ipv6OptionRepr::Pad1.emit(&mut pad_pkt);
             }
         }

+ 62 - 128
src/wire/ipv6hopbyhop.rs → src/wire/ipv6ext_header.rs

@@ -1,56 +1,38 @@
-use super::{Error, Result};
-use core::fmt;
-
-pub use super::IpProtocol as Protocol;
-use crate::wire::ipv6option::Ipv6OptionsIterator;
+#![allow(unused)]
 
-/// A read/write wrapper around an IPv6 Hop-by-Hop Options Header.
-#[derive(Debug, PartialEq, Eq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct Header<T: AsRef<[u8]>> {
-    buffer: T,
-}
+use super::IpProtocol;
+use super::{Error, Result};
 
-// Format of the Hop-by-Hop Options Header
-//
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |  Next Header  |  Hdr Ext Len  |                               |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
-// |                                                               |
-// .                                                               .
-// .                            Options                            .
-// .                                                               .
-// |                                                               |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//
-//
-// See https://tools.ietf.org/html/rfc8200#section-4.3 for details.
 mod field {
     #![allow(non_snake_case)]
 
     use crate::wire::field::*;
 
-    // Minimum size of the header.
     pub const MIN_HEADER_SIZE: usize = 8;
 
-    // 8-bit identifier of the header immediately following this header.
     pub const NXT_HDR: usize = 0;
-    // 8-bit unsigned integer. Length of the OPTIONS field in 8-octet units,
-    // not including the first 8 octets.
     pub const LENGTH: usize = 1;
-    // Variable-length field. Option-Type-specific data.
+    // Variable-length field.
     //
-    // Length of the header is in 8-octet units, not including the first 8 octets. The first two
-    // octets are the next header type and the header length.
-    pub const fn OPTIONS(length_field: u8) -> Field {
+    // Length of the header is in 8-octet units, not including the first 8 octets.
+    // The first two octets are the next header type and the header length.
+    pub const fn PAYLOAD(length_field: u8) -> Field {
         let bytes = length_field as usize * 8 + 8;
         2..bytes
     }
 }
 
+/// A read/write wrapper around an IPv6 Extension Header buffer.
+#[derive(Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct Header<T: AsRef<[u8]>> {
+    buffer: T,
+}
+
+/// Core getter methods relevant to any IPv6 extension header.
 impl<T: AsRef<[u8]>> Header<T> {
-    /// Create a raw octet buffer with an IPv6 Hop-by-Hop Options Header structure.
-    pub const fn new_unchecked(buffer: T) -> Header<T> {
+    /// Create a raw octet buffer with an IPv6 Extension Header structure.
+    pub const fn new_unchecked(buffer: T) -> Self {
         Header { buffer }
     }
 
@@ -58,7 +40,7 @@ impl<T: AsRef<[u8]>> Header<T> {
     ///
     /// [new_unchecked]: #method.new_unchecked
     /// [check_len]: #method.check_len
-    pub fn new_checked(buffer: T) -> Result<Header<T>> {
+    pub fn new_checked(buffer: T) -> Result<Self> {
         let header = Self::new_unchecked(buffer);
         header.check_len()?;
         Ok(header)
@@ -72,14 +54,13 @@ impl<T: AsRef<[u8]>> Header<T> {
     /// [set_header_len]: #method.set_header_len
     pub fn check_len(&self) -> Result<()> {
         let data = self.buffer.as_ref();
-        let len = data.len();
 
+        let len = data.len();
         if len < field::MIN_HEADER_SIZE {
             return Err(Error);
         }
 
-        let of = field::OPTIONS(data[field::LENGTH]);
-
+        let of = field::PAYLOAD(data[field::LENGTH]);
         if len < of.end {
             return Err(Error);
         }
@@ -93,40 +74,36 @@ impl<T: AsRef<[u8]>> Header<T> {
     }
 
     /// Return the next header field.
-    #[inline]
-    pub fn next_header(&self) -> Protocol {
+    pub fn next_header(&self) -> IpProtocol {
         let data = self.buffer.as_ref();
-        Protocol::from(data[field::NXT_HDR])
+        IpProtocol::from(data[field::NXT_HDR])
     }
 
-    /// Return length of the Hop-by-Hop Options header in 8-octet units, not including the first
-    /// 8 octets.
-    #[inline]
+    /// Return the header length field.
     pub fn header_len(&self) -> u8 {
         let data = self.buffer.as_ref();
         data[field::LENGTH]
     }
 }
 
-impl<'a, T: AsRef<[u8]> + ?Sized> Header<&'a T> {
-    /// Return the option data.
-    #[inline]
-    pub fn options(&self) -> &'a [u8] {
+impl<'h, T: AsRef<[u8]> + ?Sized> Header<&'h T> {
+    /// Return the payload of the IPv6 extension header.
+    pub fn payload(&self) -> &'h [u8] {
         let data = self.buffer.as_ref();
-        &data[field::OPTIONS(data[field::LENGTH])]
+        &data[field::PAYLOAD(data[field::LENGTH])]
     }
 }
 
 impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
     /// Set the next header field.
     #[inline]
-    pub fn set_next_header(&mut self, value: Protocol) {
+    pub fn set_next_header(&mut self, value: IpProtocol) {
         let data = self.buffer.as_mut();
         data[field::NXT_HDR] = value.into();
     }
 
-    /// Set the option data length. Length of the Hop-by-Hop Options header in 8-octet units,
-    /// not including the first 8 octets.
+    /// Set the extension header data length. The length of the header is
+    /// in 8-octet units, not including the first 8 octets.
     #[inline]
     pub fn set_header_len(&mut self, value: u8) {
         let data = self.buffer.as_mut();
@@ -135,78 +112,46 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
 }
 
 impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Header<&'a mut T> {
-    /// Return a mutable pointer to the option data.
+    /// Return a mutable pointer to the payload data.
     #[inline]
-    pub fn options_mut(&mut self) -> &mut [u8] {
+    pub fn payload_mut(&mut self) -> &mut [u8] {
         let data = self.buffer.as_mut();
         let len = data[field::LENGTH];
-        &mut data[field::OPTIONS(len)]
-    }
-}
-
-impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Header<&'a T> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match Repr::parse(self) {
-            Ok(repr) => write!(f, "{repr}"),
-            Err(err) => {
-                write!(f, "IPv6 Hop-by-Hop Options ({err})")?;
-                Ok(())
-            }
-        }
+        &mut data[field::PAYLOAD(len)]
     }
 }
 
-/// A high-level representation of an IPv6 Hop-by-Hop Options header.
 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct Repr<'a> {
-    /// The type of header immediately following the Hop-by-Hop Options header.
-    pub next_header: Protocol,
-    /// Length of the Hop-by-Hop Options header in 8-octet units, not including the first 8 octets.
+    pub next_header: IpProtocol,
     pub length: u8,
-    /// The options contained in the Hop-by-Hop Options header.
-    pub options: &'a [u8],
+    pub data: &'a [u8],
 }
 
 impl<'a> Repr<'a> {
-    /// Parse an IPv6 Hop-by-Hop Options Header and return a high-level representation.
-    pub fn parse<T>(header: &Header<&'a T>) -> Result<Repr<'a>>
+    /// Parse an IPv6 Extension Header Header and return a high-level representation.
+    pub fn parse<T>(header: &Header<&'a T>) -> Result<Self>
     where
         T: AsRef<[u8]> + ?Sized,
     {
-        Ok(Repr {
+        Ok(Self {
             next_header: header.next_header(),
             length: header.header_len(),
-            options: header.options(),
+            data: header.payload(),
         })
     }
 
     /// Return the length, in bytes, of a header that will be emitted from this high-level
     /// representation.
-    pub const fn buffer_len(&self) -> usize {
-        field::OPTIONS(self.length).end
+    pub const fn header_len(&self) -> usize {
+        2
     }
 
-    /// Emit a high-level representation into an IPv6 Hop-by-Hop Options Header.
+    /// Emit a high-level representation into an IPv6 Extension Header.
     pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>) {
         header.set_next_header(self.next_header);
         header.set_header_len(self.length);
-        header.options_mut().copy_from_slice(self.options);
-    }
-
-    /// Return an `Iterator` for the contained options.
-    pub fn options(&self) -> Ipv6OptionsIterator {
-        Ipv6OptionsIterator::new(self.options, self.buffer_len() - 2)
-    }
-}
-
-impl<'a> fmt::Display for Repr<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(
-            f,
-            "IPv6 Hop-by-Hop Options next_hdr={} length={} ",
-            self.next_header, self.length
-        )
     }
 }
 
@@ -254,14 +199,14 @@ mod test {
     #[test]
     fn test_header_deconstruct() {
         let header = Header::new_unchecked(&REPR_PACKET_PAD4);
-        assert_eq!(header.next_header(), Protocol::Tcp);
+        assert_eq!(header.next_header(), IpProtocol::Tcp);
         assert_eq!(header.header_len(), 0);
-        assert_eq!(header.options(), &REPR_PACKET_PAD4[2..]);
+        assert_eq!(header.payload(), &REPR_PACKET_PAD4[2..]);
 
         let header = Header::new_unchecked(&REPR_PACKET_PAD12);
-        assert_eq!(header.next_header(), Protocol::Tcp);
+        assert_eq!(header.next_header(), IpProtocol::Tcp);
         assert_eq!(header.header_len(), 1);
-        assert_eq!(header.options(), &REPR_PACKET_PAD12[2..]);
+        assert_eq!(header.payload(), &REPR_PACKET_PAD12[2..]);
     }
 
     #[test]
@@ -271,11 +216,11 @@ mod test {
         bytes.push(0);
 
         assert_eq!(
-            Header::new_unchecked(&bytes).options().len(),
+            Header::new_unchecked(&bytes).payload().len(),
             REPR_PACKET_PAD4[2..].len()
         );
         assert_eq!(
-            Header::new_unchecked(&mut bytes).options_mut().len(),
+            Header::new_unchecked(&mut bytes).payload_mut().len(),
             REPR_PACKET_PAD4[2..].len()
         );
 
@@ -284,11 +229,11 @@ mod test {
         bytes.push(0);
 
         assert_eq!(
-            Header::new_unchecked(&bytes).options().len(),
+            Header::new_unchecked(&bytes).payload().len(),
             REPR_PACKET_PAD12[2..].len()
         );
         assert_eq!(
-            Header::new_unchecked(&mut bytes).options_mut().len(),
+            Header::new_unchecked(&mut bytes).payload_mut().len(),
             REPR_PACKET_PAD12[2..].len()
         );
     }
@@ -317,9 +262,9 @@ mod test {
         assert_eq!(
             repr,
             Repr {
-                next_header: Protocol::Tcp,
+                next_header: IpProtocol::Tcp,
                 length: 0,
-                options: &REPR_PACKET_PAD4[2..]
+                data: &REPR_PACKET_PAD4[2..]
             }
         );
 
@@ -328,9 +273,9 @@ mod test {
         assert_eq!(
             repr,
             Repr {
-                next_header: Protocol::Tcp,
+                next_header: IpProtocol::Tcp,
                 length: 1,
-                options: &REPR_PACKET_PAD12[2..]
+                data: &REPR_PACKET_PAD12[2..]
             }
         );
     }
@@ -338,34 +283,23 @@ mod test {
     #[test]
     fn test_repr_emit() {
         let repr = Repr {
-            next_header: Protocol::Tcp,
+            next_header: IpProtocol::Tcp,
             length: 0,
-            options: &REPR_PACKET_PAD4[2..],
+            data: &REPR_PACKET_PAD4[2..],
         };
-        let mut bytes = [0u8; 8];
+        let mut bytes = [0u8; 2];
         let mut header = Header::new_unchecked(&mut bytes);
         repr.emit(&mut header);
-        assert_eq!(header.into_inner(), &REPR_PACKET_PAD4[..]);
+        assert_eq!(header.into_inner(), &REPR_PACKET_PAD4[..2]);
 
         let repr = Repr {
-            next_header: Protocol::Tcp,
+            next_header: IpProtocol::Tcp,
             length: 1,
-            options: &REPR_PACKET_PAD12[2..],
+            data: &REPR_PACKET_PAD12[2..],
         };
-        let mut bytes = [0u8; 16];
+        let mut bytes = [0u8; 2];
         let mut header = Header::new_unchecked(&mut bytes);
         repr.emit(&mut header);
-        assert_eq!(header.into_inner(), &REPR_PACKET_PAD12[..]);
-    }
-
-    #[test]
-    fn test_buffer_len() {
-        let header = Header::new_unchecked(&REPR_PACKET_PAD4);
-        let repr = Repr::parse(&header).unwrap();
-        assert_eq!(repr.buffer_len(), REPR_PACKET_PAD4.len());
-
-        let header = Header::new_unchecked(&REPR_PACKET_PAD12);
-        let repr = Repr::parse(&header).unwrap();
-        assert_eq!(repr.buffer_len(), REPR_PACKET_PAD12.len());
+        assert_eq!(header.into_inner(), &REPR_PACKET_PAD12[..2]);
     }
 }

+ 21 - 48
src/wire/ipv6fragment.rs

@@ -21,17 +21,17 @@ pub struct Header<T: AsRef<[u8]>> {
 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //
 // See https://tools.ietf.org/html/rfc8200#section-4.5 for details.
+//
+// **NOTE**: The fields start counting after the header length field.
 mod field {
     use crate::wire::field::*;
 
-    // 8-bit identifier of the header immediately following this header.
-    pub const NXT_HDR: usize = 0;
-    // 8-bit reserved field.
-    pub const RESERVED: usize = 1;
     // 16-bit field containing the fragment offset, reserved and more fragments values.
-    pub const FR_OF_M: Field = 2..4;
+    pub const FR_OF_M: Field = 0..2;
     // 32-bit field identifying the fragmented packet
-    pub const IDENT: Field = 4..8;
+    pub const IDENT: Field = 2..6;
+    /// 1 bit flag indicating if there are more fragments coming.
+    pub const M: usize = 1;
 }
 
 impl<T: AsRef<[u8]>> Header<T> {
@@ -68,13 +68,6 @@ impl<T: AsRef<[u8]>> Header<T> {
         self.buffer
     }
 
-    /// Return the next header field.
-    #[inline]
-    pub fn next_header(&self) -> Protocol {
-        let data = self.buffer.as_ref();
-        Protocol::from(data[field::NXT_HDR])
-    }
-
     /// Return the fragment offset field.
     #[inline]
     pub fn frag_offset(&self) -> u16 {
@@ -86,7 +79,7 @@ impl<T: AsRef<[u8]>> Header<T> {
     #[inline]
     pub fn more_frags(&self) -> bool {
         let data = self.buffer.as_ref();
-        (data[3] & 0x1) == 1
+        (data[field::M] & 0x1) == 1
     }
 
     /// Return the fragment identification value field.
@@ -98,13 +91,6 @@ impl<T: AsRef<[u8]>> Header<T> {
 }
 
 impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
-    /// Set the next header field.
-    #[inline]
-    pub fn set_next_header(&mut self, value: Protocol) {
-        let data = self.buffer.as_mut();
-        data[field::NXT_HDR] = value.into();
-    }
-
     /// Set reserved fields.
     ///
     /// Set 8-bit reserved field after the next header field.
@@ -112,11 +98,8 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
     #[inline]
     pub fn clear_reserved(&mut self) {
         let data = self.buffer.as_mut();
-
-        data[field::RESERVED] = 0;
-
         // Retain the higher order 5 bits and lower order 1 bit
-        data[3] &= 0xf9;
+        data[field::M] &= 0xf9;
     }
 
     /// Set the fragment offset field.
@@ -124,7 +107,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
     pub fn set_frag_offset(&mut self, value: u16) {
         let data = self.buffer.as_mut();
         // Retain the lower order 3 bits
-        let raw = ((value & 0x1fff) << 3) | ((data[3] & 0x7) as u16);
+        let raw = ((value & 0x1fff) << 3) | ((data[field::M] & 0x7) as u16);
         NetworkEndian::write_u16(&mut data[field::FR_OF_M], raw);
     }
 
@@ -133,8 +116,8 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
     pub fn set_more_frags(&mut self, value: bool) {
         let data = self.buffer.as_mut();
         // Retain the high order 7 bits
-        let raw = (data[3] & 0xfe) | (value as u8 & 0x1);
-        data[3] = raw;
+        let raw = (data[field::M] & 0xfe) | (value as u8 & 0x1);
+        data[field::M] = raw;
     }
 
     /// Set the fragmentation identification field.
@@ -161,8 +144,6 @@ impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Header<&'a T> {
 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct Repr {
-    /// The type of header immediately following the Fragment header.
-    pub next_header: Protocol,
     /// The offset of the data following this header, relative to the start of the Fragmentable
     /// Part of the original packet.
     pub frag_offset: u16,
@@ -179,7 +160,6 @@ impl Repr {
         T: AsRef<[u8]> + ?Sized,
     {
         Ok(Repr {
-            next_header: header.next_header(),
             frag_offset: header.frag_offset(),
             more_frags: header.more_frags(),
             ident: header.ident(),
@@ -194,7 +174,6 @@ impl Repr {
 
     /// Emit a high-level representation into an IPv6 Fragment Header.
     pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>) {
-        header.set_next_header(self.next_header);
         header.clear_reserved();
         header.set_frag_offset(self.frag_offset);
         header.set_more_frags(self.more_frags);
@@ -206,8 +185,8 @@ impl fmt::Display for Repr {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(
             f,
-            "IPv6 Fragment next_hdr={} offset={} more={} ident={}",
-            self.next_header, self.frag_offset, self.more_frags, self.ident
+            "IPv6 Fragment offset={} more={} ident={}",
+            self.frag_offset, self.more_frags, self.ident
         )
     }
 }
@@ -217,17 +196,17 @@ mod test {
     use super::*;
 
     // A Fragment Header with more fragments remaining
-    static BYTES_HEADER_MORE_FRAG: [u8; 8] = [0x6, 0x0, 0x0, 0x1, 0x0, 0x0, 0x30, 0x39];
+    static BYTES_HEADER_MORE_FRAG: [u8; 6] = [0x0, 0x1, 0x0, 0x0, 0x30, 0x39];
 
     // A Fragment Header with no more fragments remaining
-    static BYTES_HEADER_LAST_FRAG: [u8; 8] = [0x6, 0x0, 0xa, 0x0, 0x0, 0x1, 0x9, 0x32];
+    static BYTES_HEADER_LAST_FRAG: [u8; 6] = [0xa, 0x0, 0x0, 0x1, 0x9, 0x32];
 
     #[test]
     fn test_check_len() {
-        // less than 8 bytes
+        // less than 6 bytes
         assert_eq!(
             Err(Error),
-            Header::new_unchecked(&BYTES_HEADER_MORE_FRAG[..7]).check_len()
+            Header::new_unchecked(&BYTES_HEADER_MORE_FRAG[..5]).check_len()
         );
         // valid
         assert_eq!(
@@ -239,13 +218,11 @@ mod test {
     #[test]
     fn test_header_deconstruct() {
         let header = Header::new_unchecked(&BYTES_HEADER_MORE_FRAG);
-        assert_eq!(header.next_header(), Protocol::Tcp);
         assert_eq!(header.frag_offset(), 0);
         assert!(header.more_frags());
         assert_eq!(header.ident(), 12345);
 
         let header = Header::new_unchecked(&BYTES_HEADER_LAST_FRAG);
-        assert_eq!(header.next_header(), Protocol::Tcp);
         assert_eq!(header.frag_offset(), 320);
         assert!(!header.more_frags());
         assert_eq!(header.ident(), 67890);
@@ -258,7 +235,6 @@ mod test {
         assert_eq!(
             repr,
             Repr {
-                next_header: Protocol::Tcp,
                 frag_offset: 0,
                 more_frags: true,
                 ident: 12345
@@ -270,7 +246,6 @@ mod test {
         assert_eq!(
             repr,
             Repr {
-                next_header: Protocol::Tcp,
                 frag_offset: 320,
                 more_frags: false,
                 ident: 67890
@@ -281,26 +256,24 @@ mod test {
     #[test]
     fn test_repr_emit() {
         let repr = Repr {
-            next_header: Protocol::Tcp,
             frag_offset: 0,
             more_frags: true,
             ident: 12345,
         };
-        let mut bytes = [0u8; 8];
+        let mut bytes = [0u8; 6];
         let mut header = Header::new_unchecked(&mut bytes);
         repr.emit(&mut header);
-        assert_eq!(header.into_inner(), &BYTES_HEADER_MORE_FRAG[0..8]);
+        assert_eq!(header.into_inner(), &BYTES_HEADER_MORE_FRAG[0..6]);
 
         let repr = Repr {
-            next_header: Protocol::Tcp,
             frag_offset: 320,
             more_frags: false,
             ident: 67890,
         };
-        let mut bytes = [0u8; 8];
+        let mut bytes = [0u8; 6];
         let mut header = Header::new_unchecked(&mut bytes);
         repr.emit(&mut header);
-        assert_eq!(header.into_inner(), &BYTES_HEADER_LAST_FRAG[0..8]);
+        assert_eq!(header.into_inner(), &BYTES_HEADER_LAST_FRAG[0..6]);
     }
 
     #[test]

+ 3 - 17
src/wire/ipv6option.rs

@@ -322,12 +322,8 @@ impl<'a> Ipv6OptionsIterator<'a> {
     /// Create a new `Ipv6OptionsIterator`, used to iterate over the
     /// options contained in a IPv6 Extension Header (e.g. the Hop-by-Hop
     /// header).
-    ///
-    /// # Panics
-    /// This function panics if the `length` provided is larger than the
-    /// length of the `data` buffer.
-    pub fn new(data: &'a [u8], length: usize) -> Ipv6OptionsIterator<'a> {
-        assert!(length <= data.len());
+    pub fn new(data: &'a [u8]) -> Ipv6OptionsIterator<'a> {
+        let length = data.len();
         Ipv6OptionsIterator {
             pos: 0,
             hit_error: false,
@@ -591,10 +587,7 @@ mod test {
             0x08, 0x00,
         ];
 
-        let mut iterator = Ipv6OptionsIterator::new(&options, 0);
-        assert_eq!(iterator.next(), None);
-
-        iterator = Ipv6OptionsIterator::new(&options, 16);
+        let iterator = Ipv6OptionsIterator::new(&options);
         for (i, opt) in iterator.enumerate() {
             match (i, opt) {
                 (0, Ok(Repr::Pad1)) => continue,
@@ -615,11 +608,4 @@ mod test {
             }
         }
     }
-
-    #[test]
-    #[should_panic(expected = "length <= data.len()")]
-    fn test_options_iter_truncated() {
-        let options = [0x01, 0x02, 0x00, 0x00];
-        let _ = Ipv6OptionsIterator::new(&options, 5);
-    }
 }

+ 74 - 142
src/wire/ipv6routing.rs

@@ -1,7 +1,6 @@
 use super::{Error, Result};
 use core::fmt;
 
-use crate::wire::IpProtocol as Protocol;
 use crate::wire::Ipv6Address as Address;
 
 enum_with_unknown! {
@@ -70,31 +69,20 @@ pub struct Header<T: AsRef<[u8]>> {
 //
 //
 // See https://tools.ietf.org/html/rfc8200#section-4.4 for details.
+//
+// **NOTE**: The fields start counting after the header length field.
 mod field {
     #![allow(non_snake_case)]
 
     use crate::wire::field::*;
 
     // Minimum size of the header.
-    pub const MIN_HEADER_SIZE: usize = 4;
+    pub const MIN_HEADER_SIZE: usize = 2;
 
-    // 8-bit identifier of the header immediately following this header.
-    pub const NXT_HDR: usize = 0;
-    // 8-bit unsigned integer. Length of the DATA field in 8-octet units,
-    // not including the first 8 octets.
-    pub const LENGTH: usize = 1;
     // 8-bit identifier of a particular Routing header variant.
-    pub const TYPE: usize = 2;
+    pub const TYPE: usize = 0;
     // 8-bit unsigned integer. The number of route segments remaining.
-    pub const SEG_LEFT: usize = 3;
-    // Variable-length field. Routing-Type-specific data.
-    //
-    // Length of the header is in 8-octet units, not including the first 8 octets. The first four
-    // octets are the next header type, the header length, routing type and segments left.
-    pub const fn DATA(length_field: u8) -> Field {
-        let bytes = length_field as usize * 8 + 8;
-        4..bytes
-    }
+    pub const SEG_LEFT: usize = 1;
 
     // The Type 2 Routing Header has the following format:
     //
@@ -113,7 +101,7 @@ mod field {
     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
     // 16-byte field containing the home address of the destination mobile node.
-    pub const HOME_ADDRESS: Field = 8..24;
+    pub const HOME_ADDRESS: Field = 6..22;
 
     // The RPL Source Routing Header has the following format:
     //
@@ -130,20 +118,17 @@ mod field {
     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
     // 8-bit field containing the CmprI and CmprE values.
-    pub const CMPR: usize = 4;
+    pub const CMPR: usize = 2;
     // 8-bit field containing the Pad value.
-    pub const PAD: usize = 5;
+    pub const PAD: usize = 3;
     // Variable length field containing addresses
-    pub const fn ADDRESSES(length_field: u8) -> Field {
-        let data = DATA(length_field);
-        8..data.end
-    }
+    pub const ADDRESSES: usize = 6;
 }
 
 /// Core getter methods relevant to any routing type.
 impl<T: AsRef<[u8]>> Header<T> {
     /// Create a raw octet buffer with an IPv6 Routing Header structure.
-    pub const fn new(buffer: T) -> Header<T> {
+    pub const fn new_unchecked(buffer: T) -> Header<T> {
         Header { buffer }
     }
 
@@ -152,7 +137,7 @@ impl<T: AsRef<[u8]>> Header<T> {
     /// [new_unchecked]: #method.new_unchecked
     /// [check_len]: #method.check_len
     pub fn new_checked(buffer: T) -> Result<Header<T>> {
-        let header = Self::new(buffer);
+        let header = Self::new_unchecked(buffer);
         header.check_len()?;
         Ok(header)
     }
@@ -169,15 +154,10 @@ impl<T: AsRef<[u8]>> Header<T> {
             return Err(Error);
         }
 
-        if len < field::DATA(self.header_len()).end {
-            return Err(Error);
-        }
-
-        // The header lenght field could be wrong and thus we need to check this as well:
-        if matches!(self.routing_type(), Type::Type2)
-            && field::DATA(self.header_len()).end != field::HOME_ADDRESS.end
-        {
-            return Err(Error);
+        match self.routing_type() {
+            Type::Type2 if len < field::HOME_ADDRESS.end => return Err(Error),
+            Type::Rpl if len < field::ADDRESSES => return Err(Error),
+            _ => (),
         }
 
         Ok(())
@@ -188,21 +168,6 @@ impl<T: AsRef<[u8]>> Header<T> {
         self.buffer
     }
 
-    /// Return the next header field.
-    #[inline]
-    pub fn next_header(&self) -> Protocol {
-        let data = self.buffer.as_ref();
-        Protocol::from(data[field::NXT_HDR])
-    }
-
-    /// Return the header length field. Length of the Routing header in 8-octet units,
-    /// not including the first 8 octets.
-    #[inline]
-    pub fn header_len(&self) -> u8 {
-        let data = self.buffer.as_ref();
-        data[field::LENGTH]
-    }
-
     /// Return the routing type field.
     #[inline]
     pub fn routing_type(&self) -> Type {
@@ -265,26 +230,12 @@ impl<T: AsRef<[u8]>> Header<T> {
     /// This function may panic if this header is not the RPL Source Routing Header routing type.
     pub fn addresses(&self) -> &[u8] {
         let data = self.buffer.as_ref();
-        &data[field::ADDRESSES(data[field::LENGTH])]
+        &data[field::ADDRESSES..]
     }
 }
 
 /// Core setter methods relevant to any routing type.
 impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
-    /// Set the next header field.
-    #[inline]
-    pub fn set_next_header(&mut self, value: Protocol) {
-        let data = self.buffer.as_mut();
-        data[field::NXT_HDR] = value.into();
-    }
-
-    /// Set the option data length. Length of the Routing header in 8-octet units.
-    #[inline]
-    pub fn set_header_len(&mut self, value: u8) {
-        let data = self.buffer.as_mut();
-        data[field::LENGTH] = value;
-    }
-
     /// Set the routing type.
     #[inline]
     pub fn set_routing_type(&mut self, value: Type) {
@@ -376,8 +327,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
     /// This function may panic if this header is not the RPL Source Routing Header routing type.
     pub fn set_addresses(&mut self, value: &[u8]) {
         let data = self.buffer.as_mut();
-        let len = data[field::LENGTH];
-        let addresses = &mut data[field::ADDRESSES(len)];
+        let addresses = &mut data[field::ADDRESSES..];
         addresses.copy_from_slice(value);
     }
 }
@@ -400,20 +350,12 @@ impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Header<&'a T> {
 #[non_exhaustive]
 pub enum Repr<'a> {
     Type2 {
-        /// The type of header immediately following the Routing header.
-        next_header: Protocol,
-        /// Length of the Routing header in 8-octet units, not including the first 8 octets.
-        length: u8,
         /// Number of route segments remaining.
         segments_left: u8,
         /// The home address of the destination mobile node.
         home_address: Address,
     },
     Rpl {
-        /// The type of header immediately following the Routing header.
-        next_header: Protocol,
-        /// Length of the Routing header in 8-octet units, not including the first 8 octets.
-        length: u8,
         /// Number of route segments remaining.
         segments_left: u8,
         /// Number of prefix octets from each segment, except the last segment, that are elided.
@@ -436,14 +378,10 @@ impl<'a> Repr<'a> {
     {
         match header.routing_type() {
             Type::Type2 => Ok(Repr::Type2 {
-                next_header: header.next_header(),
-                length: header.header_len(),
                 segments_left: header.segments_left(),
                 home_address: header.home_address(),
             }),
             Type::Rpl => Ok(Repr::Rpl {
-                next_header: header.next_header(),
-                length: header.header_len(),
                 segments_left: header.segments_left(),
                 cmpr_i: header.cmpr_i(),
                 cmpr_e: header.cmpr_e(),
@@ -459,7 +397,9 @@ impl<'a> Repr<'a> {
     /// representation.
     pub const fn buffer_len(&self) -> usize {
         match self {
-            &Repr::Rpl { length, .. } | &Repr::Type2 { length, .. } => field::DATA(length).end,
+            // Routing Type + Segments Left + Reserved + Home Address
+            Repr::Type2 { home_address, .. } => 2 + 4 + home_address.as_bytes().len(),
+            Repr::Rpl { addresses, .. } => 2 + 4 + addresses.len(),
         }
     }
 
@@ -467,29 +407,21 @@ impl<'a> Repr<'a> {
     pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>) {
         match *self {
             Repr::Type2 {
-                next_header,
-                length,
                 segments_left,
                 home_address,
             } => {
-                header.set_next_header(next_header);
-                header.set_header_len(length);
                 header.set_routing_type(Type::Type2);
                 header.set_segments_left(segments_left);
                 header.clear_reserved();
                 header.set_home_address(home_address);
             }
             Repr::Rpl {
-                next_header,
-                length,
                 segments_left,
                 cmpr_i,
                 cmpr_e,
                 pad,
                 addresses,
             } => {
-                header.set_next_header(next_header);
-                header.set_header_len(length);
                 header.set_routing_type(Type::Rpl);
                 header.set_segments_left(segments_left);
                 header.set_cmpr_i(cmpr_i);
@@ -506,32 +438,33 @@ impl<'a> fmt::Display for Repr<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             Repr::Type2 {
-                next_header,
-                length,
                 segments_left,
                 home_address,
             } => {
                 write!(
                     f,
-                    "IPv6 Routing next_hdr={} length={} type={} seg_left={} home_address={}",
-                    next_header,
-                    length,
+                    "IPv6 Routing type={} seg_left={} home_address={}",
                     Type::Type2,
                     segments_left,
                     home_address
                 )
             }
             Repr::Rpl {
-                next_header,
-                length,
                 segments_left,
                 cmpr_i,
                 cmpr_e,
                 pad,
                 ..
             } => {
-                write!(f, "IPv6 Routing next_hdr={} length={} type={} seg_left={} cmpr_i={} cmpr_e={} pad={}",
-                       next_header, length, Type::Rpl, segments_left, cmpr_i, cmpr_e, pad)
+                write!(
+                    f,
+                    "IPv6 Routing type={} seg_left={} cmpr_i={} cmpr_e={} pad={}",
+                    Type::Rpl,
+                    segments_left,
+                    cmpr_i,
+                    cmpr_e,
+                    pad
+                )
             }
         }
     }
@@ -542,30 +475,26 @@ mod test {
     use super::*;
 
     // A Type 2 Routing Header
-    static BYTES_TYPE2: [u8; 24] = [
-        0x6, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-        0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+    static BYTES_TYPE2: [u8; 22] = [
+        0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        0x0, 0x0, 0x0, 0x1,
     ];
 
     // A representation of a Type 2 Routing header
     static REPR_TYPE2: Repr = Repr::Type2 {
-        next_header: Protocol::Tcp,
-        length: 2,
         segments_left: 1,
         home_address: Address::LOOPBACK,
     };
 
     // A Source Routing Header with full IPv6 addresses in bytes
-    static BYTES_SRH_FULL: [u8; 40] = [
-        0x6, 0x4, 0x3, 0x2, 0x0, 0x0, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-        0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-        0x0, 0x0, 0x3, 0x1,
+    static BYTES_SRH_FULL: [u8; 38] = [
+        0x3, 0x2, 0x0, 0x0, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        0x0, 0x0, 0x0, 0x2, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        0x3, 0x1,
     ];
 
     // A representation of a Source Routing Header with full IPv6 addresses
     static REPR_SRH_FULL: Repr = Repr::Rpl {
-        next_header: Protocol::Tcp,
-        length: 4,
         segments_left: 2,
         cmpr_i: 0,
         cmpr_e: 0,
@@ -577,14 +506,12 @@ mod test {
     };
 
     // A Source Routing Header with elided IPv6 addresses in bytes
-    static BYTES_SRH_ELIDED: [u8; 16] = [
-        0x6, 0x1, 0x3, 0x2, 0xfe, 0x50, 0x0, 0x0, 0x2, 0x3, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
+    static BYTES_SRH_ELIDED: [u8; 14] = [
+        0x3, 0x2, 0xfe, 0x50, 0x0, 0x0, 0x2, 0x3, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
     ];
 
     // A representation of a Source Routing Header with elided IPv6 addresses
     static REPR_SRH_ELIDED: Repr = Repr::Rpl {
-        next_header: Protocol::Tcp,
-        length: 1,
         segments_left: 2,
         cmpr_i: 15,
         cmpr_e: 14,
@@ -595,41 +522,46 @@ mod test {
     #[test]
     fn test_check_len() {
         // less than min header size
-        assert_eq!(Err(Error), Header::new(&BYTES_TYPE2[..3]).check_len());
-        assert_eq!(Err(Error), Header::new(&BYTES_SRH_FULL[..3]).check_len());
-        assert_eq!(Err(Error), Header::new(&BYTES_SRH_ELIDED[..3]).check_len());
-        // less than specified length field
-        assert_eq!(Err(Error), Header::new(&BYTES_TYPE2[..23]).check_len());
-        assert_eq!(Err(Error), Header::new(&BYTES_SRH_FULL[..39]).check_len());
-        assert_eq!(Err(Error), Header::new(&BYTES_SRH_ELIDED[..11]).check_len());
+        assert_eq!(
+            Err(Error),
+            Header::new_unchecked(&BYTES_TYPE2[..3]).check_len()
+        );
+        assert_eq!(
+            Err(Error),
+            Header::new_unchecked(&BYTES_SRH_FULL[..3]).check_len()
+        );
+        assert_eq!(
+            Err(Error),
+            Header::new_unchecked(&BYTES_SRH_ELIDED[..3]).check_len()
+        );
         // valid
-        assert_eq!(Ok(()), Header::new(&BYTES_TYPE2[..]).check_len());
-        assert_eq!(Ok(()), Header::new(&BYTES_SRH_FULL[..]).check_len());
-        assert_eq!(Ok(()), Header::new(&BYTES_SRH_ELIDED[..]).check_len());
+        assert_eq!(Ok(()), Header::new_unchecked(&BYTES_TYPE2[..]).check_len());
+        assert_eq!(
+            Ok(()),
+            Header::new_unchecked(&BYTES_SRH_FULL[..]).check_len()
+        );
+        assert_eq!(
+            Ok(()),
+            Header::new_unchecked(&BYTES_SRH_ELIDED[..]).check_len()
+        );
     }
 
     #[test]
     fn test_header_deconstruct() {
-        let header = Header::new(&BYTES_TYPE2[..]);
-        assert_eq!(header.next_header(), Protocol::Tcp);
-        assert_eq!(header.header_len(), 2);
+        let header = Header::new_unchecked(&BYTES_TYPE2[..]);
         assert_eq!(header.routing_type(), Type::Type2);
         assert_eq!(header.segments_left(), 1);
         assert_eq!(header.home_address(), Address::LOOPBACK);
 
-        let header = Header::new(&BYTES_SRH_FULL[..]);
-        assert_eq!(header.next_header(), Protocol::Tcp);
-        assert_eq!(header.header_len(), 4);
+        let header = Header::new_unchecked(&BYTES_SRH_FULL[..]);
         assert_eq!(header.routing_type(), Type::Rpl);
         assert_eq!(header.segments_left(), 2);
-        assert_eq!(header.addresses(), &BYTES_SRH_FULL[8..]);
+        assert_eq!(header.addresses(), &BYTES_SRH_FULL[6..]);
 
-        let header = Header::new(&BYTES_SRH_ELIDED[..]);
-        assert_eq!(header.next_header(), Protocol::Tcp);
-        assert_eq!(header.header_len(), 1);
+        let header = Header::new_unchecked(&BYTES_SRH_ELIDED[..]);
         assert_eq!(header.routing_type(), Type::Rpl);
         assert_eq!(header.segments_left(), 2);
-        assert_eq!(header.addresses(), &BYTES_SRH_ELIDED[8..]);
+        assert_eq!(header.addresses(), &BYTES_SRH_ELIDED[6..]);
     }
 
     #[test]
@@ -649,26 +581,26 @@ mod test {
 
     #[test]
     fn test_repr_emit() {
-        let mut bytes = [0u8; 24];
-        let mut header = Header::new(&mut bytes[..]);
+        let mut bytes = [0u8; 22];
+        let mut header = Header::new_unchecked(&mut bytes[..]);
         REPR_TYPE2.emit(&mut header);
         assert_eq!(header.into_inner(), &BYTES_TYPE2[..]);
 
-        let mut bytes = [0u8; 40];
-        let mut header = Header::new(&mut bytes[..]);
+        let mut bytes = [0u8; 38];
+        let mut header = Header::new_unchecked(&mut bytes[..]);
         REPR_SRH_FULL.emit(&mut header);
         assert_eq!(header.into_inner(), &BYTES_SRH_FULL[..]);
 
-        let mut bytes = [0u8; 16];
-        let mut header = Header::new(&mut bytes[..]);
+        let mut bytes = [0u8; 14];
+        let mut header = Header::new_unchecked(&mut bytes[..]);
         REPR_SRH_ELIDED.emit(&mut header);
         assert_eq!(header.into_inner(), &BYTES_SRH_ELIDED[..]);
     }
 
     #[test]
     fn test_buffer_len() {
-        assert_eq!(REPR_TYPE2.buffer_len(), 24);
-        assert_eq!(REPR_SRH_FULL.buffer_len(), 40);
-        assert_eq!(REPR_SRH_ELIDED.buffer_len(), 16);
+        assert_eq!(REPR_TYPE2.buffer_len(), 22);
+        assert_eq!(REPR_SRH_FULL.buffer_len(), 38);
+        assert_eq!(REPR_SRH_ELIDED.buffer_len(), 14);
     }
 }

+ 11 - 4
src/wire/mod.rs

@@ -101,9 +101,9 @@ mod ipv4;
 #[cfg(feature = "proto-ipv6")]
 mod ipv6;
 #[cfg(feature = "proto-ipv6")]
-mod ipv6fragment;
+mod ipv6ext_header;
 #[cfg(feature = "proto-ipv6")]
-mod ipv6hopbyhop;
+mod ipv6fragment;
 #[cfg(feature = "proto-ipv6")]
 mod ipv6option;
 #[cfg(feature = "proto-ipv6")]
@@ -190,12 +190,19 @@ pub use self::ipv6::{
 
 #[cfg(feature = "proto-ipv6")]
 pub use self::ipv6option::{
-    FailureType as Ipv6OptionFailureType, Ipv6Option, Repr as Ipv6OptionRepr,
+    FailureType as Ipv6OptionFailureType, Ipv6Option, Ipv6OptionsIterator, Repr as Ipv6OptionRepr,
     Type as Ipv6OptionType,
 };
 
 #[cfg(feature = "proto-ipv6")]
-pub use self::ipv6hopbyhop::{Header as Ipv6HopByHopHeader, Repr as Ipv6HopByHopRepr};
+pub use self::ipv6ext_header::{Header as Ipv6ExtHeader, Repr as Ipv6ExtHeaderRepr};
+
+#[cfg(feature = "proto-ipv6")]
+/// A read/write wrapper around an IPv6 Hop-By-Hop header.
+pub type Ipv6HopByHopHeader<T> = Ipv6ExtHeader<T>;
+#[cfg(feature = "proto-ipv6")]
+/// A high-level representation of an IPv6 Hop-By-Hop heade.
+pub type Ipv6HopByHopRepr<'a> = Ipv6ExtHeaderRepr<'a>;
 
 #[cfg(feature = "proto-ipv6")]
 pub use self::ipv6fragment::{Header as Ipv6FragmentHeader, Repr as Ipv6FragmentRepr};