瀏覽代碼

Merge #687

687: Add address context information for resolving 6LoWPAN addresses r=thvdveld a=thvdveld

Implements [3.1.2. Context Identifier Extension](https://www.rfc-editor.org/rfc/rfc6282#section-3.1.2)

Co-authored-by: Thibaut Vandervelden <thvdveld@vub.be>
bors[bot] 2 年之前
父節點
當前提交
e66cdf495a
共有 4 個文件被更改,包括 218 次插入77 次删除
  1. 1 0
      fuzz/fuzz_targets/sixlowpan_packet.rs
  2. 30 0
      src/iface/interface.rs
  3. 1 1
      src/wire/mod.rs
  4. 186 76
      src/wire/sixlowpan.rs

+ 1 - 0
fuzz/fuzz_targets/sixlowpan_packet.rs

@@ -43,6 +43,7 @@ fuzz_target!(|fuzz: SixlowpanPacketFuzzer| {
                     &frame,
                     fuzz.ll_src_addr.map(Into::into),
                     fuzz.ll_dst_addr.map(Into::into),
+                    &[],
                 ) {
                     let mut buffer = vec![0; iphc_repr.buffer_len()];
                     let mut iphc_frame = SixlowpanIphcPacket::new_unchecked(&mut buffer[..]);

+ 30 - 0
src/iface/interface.rs

@@ -247,6 +247,8 @@ pub struct InterfaceInner<'a> {
     pan_id: Option<Ieee802154Pan>,
     #[cfg(feature = "proto-ipv4-fragmentation")]
     ipv4_id: u16,
+    #[cfg(feature = "proto-sixlowpan")]
+    sixlowpan_address_context: &'a [SixlowpanAddressContext<'a>],
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     tag: u16,
     ip_addrs: ManagedSlice<'a, IpCidr>,
@@ -289,6 +291,9 @@ pub struct InterfaceBuilder<'a> {
     sixlowpan_reassembly_buffer_timeout: Duration,
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     sixlowpan_out_buffer: ManagedSlice<'a, u8>,
+
+    #[cfg(feature = "proto-sixlowpan")]
+    sixlowpan_address_context: &'a [SixlowpanAddressContext<'a>],
 }
 
 impl<'a> InterfaceBuilder<'a> {
@@ -362,6 +367,9 @@ let iface = builder.finalize(&mut device);
             sixlowpan_reassembly_buffer_timeout: Duration::from_secs(60),
             #[cfg(feature = "proto-sixlowpan-fragmentation")]
             sixlowpan_out_buffer: ManagedSlice::Borrowed(&mut [][..]),
+
+            #[cfg(feature = "proto-sixlowpan")]
+            sixlowpan_address_context: &[],
         }
     }
 
@@ -473,12 +481,14 @@ let iface = builder.finalize(&mut device);
         self
     }
 
+    /// Set the IPv4 reassembly buffer the interface will use.
     #[cfg(feature = "proto-ipv4-fragmentation")]
     pub fn ipv4_reassembly_buffer(mut self, storage: PacketAssemblerSet<'a, Ipv4FragKey>) -> Self {
         self.ipv4_fragments = storage;
         self
     }
 
+    /// Set the IPv4 fragments buffer the interface will use.
     #[cfg(feature = "proto-ipv4-fragmentation")]
     pub fn ipv4_fragmentation_buffer<T>(mut self, storage: T) -> Self
     where
@@ -488,6 +498,17 @@ let iface = builder.finalize(&mut device);
         self
     }
 
+    /// Set the address contexts the interface will use.
+    #[cfg(feature = "proto-sixlowpan")]
+    pub fn sixlowpan_address_context(
+        mut self,
+        sixlowpan_address_context: &'a [SixlowpanAddressContext<'a>],
+    ) -> Self {
+        self.sixlowpan_address_context = sixlowpan_address_context;
+        self
+    }
+
+    /// Set the 6LoWPAN reassembly buffer the interface will use.
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     pub fn sixlowpan_reassembly_buffer(
         mut self,
@@ -497,6 +518,7 @@ let iface = builder.finalize(&mut device);
         self
     }
 
+    /// Set the timeout value the 6LoWPAN reassembly buffer will use.
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     pub fn sixlowpan_reassembly_buffer_timeout(mut self, timeout: Duration) -> Self {
         if timeout > Duration::from_secs(60) {
@@ -506,6 +528,7 @@ let iface = builder.finalize(&mut device);
         self
     }
 
+    /// Set the 6LoWPAN fragments buffer the interface will use.
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     pub fn sixlowpan_fragmentation_buffer<T>(mut self, storage: T) -> Self
     where
@@ -651,6 +674,8 @@ let iface = builder.finalize(&mut device);
                 tag,
                 #[cfg(feature = "proto-ipv4-fragmentation")]
                 ipv4_id,
+                #[cfg(feature = "proto-sixlowpan")]
+                sixlowpan_address_context: &[],
                 rand,
             },
         }
@@ -1534,6 +1559,9 @@ impl<'a> InterfaceInner<'a> {
             #[cfg(feature = "proto-sixlowpan-fragmentation")]
             tag: 1,
 
+            #[cfg(feature = "proto-sixlowpan")]
+            sixlowpan_address_context: &[],
+
             #[cfg(feature = "proto-ipv4-fragmentation")]
             ipv4_id: 1,
 
@@ -1804,6 +1832,7 @@ impl<'a> InterfaceInner<'a> {
                         &iphc,
                         ieee802154_repr.src_addr,
                         ieee802154_repr.dst_addr,
+                        self.sixlowpan_address_context
                     ));
 
                     // The uncompressed header size always starts with 40, since this is the size
@@ -1888,6 +1917,7 @@ impl<'a> InterfaceInner<'a> {
             &iphc_packet,
             ieee802154_repr.src_addr,
             ieee802154_repr.dst_addr,
+            self.sixlowpan_address_context,
         ));
 
         let payload = iphc_packet.payload();

+ 1 - 1
src/wire/mod.rs

@@ -151,7 +151,7 @@ pub use self::sixlowpan::{
         NhcPacket as SixlowpanNhcPacket, UdpNhcPacket as SixlowpanUdpNhcPacket,
         UdpNhcRepr as SixlowpanUdpNhcRepr,
     },
-    NextHeader as SixlowpanNextHeader, SixlowpanPacket,
+    AddressContext as SixlowpanAddressContext, NextHeader as SixlowpanNextHeader, SixlowpanPacket,
 };
 
 #[cfg(feature = "medium-ieee802154")]

+ 186 - 76
src/wire/sixlowpan.rs

@@ -2,11 +2,25 @@
 //! IEEE802.154-based networks.
 //!
 //! [RFC 6282]: https://datatracker.ietf.org/doc/html/rfc6282
+use core::ops::Deref;
+
 use super::{Error, Result};
 use crate::wire::ieee802154::Address as LlAddress;
 use crate::wire::ipv6;
 use crate::wire::IpProtocol;
 
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct AddressContext<'a>(pub &'a [u8]);
+
+impl<'a> Deref for AddressContext<'a> {
+    type Target = [u8];
+
+    fn deref(&self) -> &Self::Target {
+        self.0
+    }
+}
+
 /// The representation of an unresolved address. 6LoWPAN compression of IPv6 addresses can be with
 /// and without context information. The decompression with context information is not yet
 /// implemented.
@@ -14,7 +28,7 @@ use crate::wire::IpProtocol;
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum UnresolvedAddress<'a> {
     WithoutContext(AddressMode<'a>),
-    WithContext(AddressMode<'a>),
+    WithContext((usize, AddressMode<'a>)),
     Reserved,
 }
 
@@ -51,8 +65,30 @@ const LINK_LOCAL_PREFIX: [u8; 2] = [0xfe, 0x80];
 const EUI64_MIDDLE_VALUE: [u8; 2] = [0xff, 0xfe];
 
 impl<'a> UnresolvedAddress<'a> {
-    pub fn resolve(self, ll_address: Option<LlAddress>) -> Result<ipv6::Address> {
+    pub fn resolve(
+        self,
+        ll_address: Option<LlAddress>,
+        addr_context: &[AddressContext<'_>],
+    ) -> Result<ipv6::Address> {
         let mut bytes = [0; 16];
+
+        let copy_context = |index: usize, bytes: &mut [u8]| -> Result<()> {
+            if index >= addr_context.len() {
+                return Err(Error);
+            }
+
+            let context = addr_context[index];
+            let len = context.len();
+
+            if len > 8 {
+                return Err(Error);
+            }
+
+            bytes[..len].copy_from_slice(&context);
+
+            Ok(())
+        };
+
         match self {
             UnresolvedAddress::WithoutContext(mode) => match mode {
                 AddressMode::FullInline(addr) => Ok(ipv6::Address::from_bytes(addr)),
@@ -104,8 +140,35 @@ impl<'a> UnresolvedAddress<'a> {
                 _ => Err(Error),
             },
             UnresolvedAddress::WithContext(mode) => match mode {
-                AddressMode::Unspecified => Ok(ipv6::Address::UNSPECIFIED),
-                AddressMode::NotSupported => Err(Error),
+                (_, AddressMode::Unspecified) => Ok(ipv6::Address::UNSPECIFIED),
+                (index, AddressMode::InLine64bits(inline)) => {
+                    copy_context(index, &mut bytes[..])?;
+                    bytes[16 - inline.len()..].copy_from_slice(inline);
+                    Ok(ipv6::Address::from_bytes(&bytes[..]))
+                }
+                (index, AddressMode::InLine16bits(inline)) => {
+                    copy_context(index, &mut bytes[..])?;
+                    bytes[16 - inline.len()..].copy_from_slice(inline);
+                    Ok(ipv6::Address::from_bytes(&bytes[..]))
+                }
+                (index, AddressMode::FullyElided) => {
+                    match ll_address {
+                        Some(LlAddress::Short(ll)) => {
+                            bytes[11..13].copy_from_slice(&EUI64_MIDDLE_VALUE[..]);
+                            bytes[14..].copy_from_slice(&ll);
+                        }
+                        Some(addr @ LlAddress::Extended(_)) => match addr.as_eui_64() {
+                            Some(addr) => bytes[8..].copy_from_slice(&addr),
+                            None => return Err(Error),
+                        },
+                        Some(LlAddress::Absent) => return Err(Error),
+                        None => return Err(Error),
+                    }
+
+                    copy_context(index, &mut bytes[..])?;
+
+                    Ok(ipv6::Address::from_bytes(&bytes[..]))
+                }
                 _ => Err(Error),
             },
             UnresolvedAddress::Reserved => Err(Error),
@@ -421,7 +484,10 @@ pub mod iphc {
     //!
     //! [RFC 6282 § 3.1]: https://datatracker.ietf.org/doc/html/rfc6282#section-3.1
 
-    use super::{AddressMode, Error, NextHeader, Result, UnresolvedAddress, DISPATCH_IPHC_HEADER};
+    use super::{
+        AddressContext, AddressMode, Error, NextHeader, Result, UnresolvedAddress,
+        DISPATCH_IPHC_HEADER,
+    };
     use crate::wire::{ieee802154::Address as LlAddress, ipv6, IpProtocol};
     use byteorder::{ByteOrder, NetworkEndian};
 
@@ -573,7 +639,7 @@ pub mod iphc {
         pub fn src_context_id(&self) -> Option<u8> {
             if self.cid_field() == 1 {
                 let data = self.buffer.as_ref();
-                Some(data[1] >> 4)
+                Some(data[2] >> 4)
             } else {
                 None
             }
@@ -583,7 +649,7 @@ pub mod iphc {
         pub fn dst_context_id(&self) -> Option<u8> {
             if self.cid_field() == 1 {
                 let data = self.buffer.as_ref();
-                Some(data[1] & 0x0f)
+                Some(data[2] & 0x0f)
             } else {
                 None
             }
@@ -640,30 +706,52 @@ pub mod iphc {
                 + self.next_header_size()
                 + self.hop_limit_size()) as usize;
 
+            let data = self.buffer.as_ref();
             match (self.sac_field(), self.sam_field()) {
-                (0, 0b00) => {
-                    let data = self.buffer.as_ref();
-                    Ok(UnresolvedAddress::WithoutContext(AddressMode::FullInline(
-                        &data[start..][..16],
-                    )))
+                (0, 0b00) => Ok(UnresolvedAddress::WithoutContext(AddressMode::FullInline(
+                    &data[start..][..16],
+                ))),
+                (0, 0b01) => Ok(UnresolvedAddress::WithoutContext(
+                    AddressMode::InLine64bits(&data[start..][..8]),
+                )),
+                (0, 0b10) => Ok(UnresolvedAddress::WithoutContext(
+                    AddressMode::InLine16bits(&data[start..][..2]),
+                )),
+                (0, 0b11) => Ok(UnresolvedAddress::WithoutContext(AddressMode::FullyElided)),
+                (1, 0b00) => Ok(UnresolvedAddress::WithContext((
+                    0,
+                    AddressMode::Unspecified,
+                ))),
+                (1, 0b01) => {
+                    if let Some(id) = self.src_context_id() {
+                        Ok(UnresolvedAddress::WithContext((
+                            id as usize,
+                            AddressMode::InLine64bits(&data[start..][..8]),
+                        )))
+                    } else {
+                        Err(Error)
+                    }
                 }
-                (0, 0b01) => {
-                    let data = self.buffer.as_ref();
-                    Ok(UnresolvedAddress::WithoutContext(
-                        AddressMode::InLine64bits(&data[start..][..8]),
-                    ))
+                (1, 0b10) => {
+                    if let Some(id) = self.src_context_id() {
+                        Ok(UnresolvedAddress::WithContext((
+                            id as usize,
+                            AddressMode::InLine16bits(&data[start..][..2]),
+                        )))
+                    } else {
+                        Err(Error)
+                    }
                 }
-                (0, 0b10) => {
-                    let data = self.buffer.as_ref();
-                    Ok(UnresolvedAddress::WithoutContext(
-                        AddressMode::InLine16bits(&data[start..][..2]),
-                    ))
+                (1, 0b11) => {
+                    if let Some(id) = self.src_context_id() {
+                        Ok(UnresolvedAddress::WithContext((
+                            id as usize,
+                            AddressMode::FullyElided,
+                        )))
+                    } else {
+                        Err(Error)
+                    }
                 }
-                (0, 0b11) => Ok(UnresolvedAddress::WithoutContext(AddressMode::FullyElided)),
-                (1, 0b00) => Ok(UnresolvedAddress::WithContext(AddressMode::Unspecified)),
-                (1, 0b01) => Ok(UnresolvedAddress::WithContext(AddressMode::NotSupported)),
-                (1, 0b10) => Ok(UnresolvedAddress::WithContext(AddressMode::NotSupported)),
-                (1, 0b11) => Ok(UnresolvedAddress::WithContext(AddressMode::NotSupported)),
                 _ => Err(Error),
             }
         }
@@ -676,55 +764,65 @@ pub mod iphc {
                 + self.hop_limit_size()
                 + self.src_address_size()) as usize;
 
+            let data = self.buffer.as_ref();
             match (self.m_field(), self.dac_field(), self.dam_field()) {
-                (0, 0, 0b00) => {
-                    let data = self.buffer.as_ref();
-                    Ok(UnresolvedAddress::WithoutContext(AddressMode::FullInline(
-                        &data[start..][..16],
-                    )))
-                }
-                (0, 0, 0b01) => {
-                    let data = self.buffer.as_ref();
-                    Ok(UnresolvedAddress::WithoutContext(
-                        AddressMode::InLine64bits(&data[start..][..8]),
-                    ))
-                }
-                (0, 0, 0b10) => {
-                    let data = self.buffer.as_ref();
-                    Ok(UnresolvedAddress::WithoutContext(
-                        AddressMode::InLine16bits(&data[start..][..2]),
-                    ))
-                }
+                (0, 0, 0b00) => Ok(UnresolvedAddress::WithoutContext(AddressMode::FullInline(
+                    &data[start..][..16],
+                ))),
+                (0, 0, 0b01) => Ok(UnresolvedAddress::WithoutContext(
+                    AddressMode::InLine64bits(&data[start..][..8]),
+                )),
+                (0, 0, 0b10) => Ok(UnresolvedAddress::WithoutContext(
+                    AddressMode::InLine16bits(&data[start..][..2]),
+                )),
                 (0, 0, 0b11) => Ok(UnresolvedAddress::WithoutContext(AddressMode::FullyElided)),
                 (0, 1, 0b00) => Ok(UnresolvedAddress::Reserved),
-                (0, 1, 0b01) => Ok(UnresolvedAddress::WithContext(AddressMode::NotSupported)),
-                (0, 1, 0b10) => Ok(UnresolvedAddress::WithContext(AddressMode::NotSupported)),
-                (0, 1, 0b11) => Ok(UnresolvedAddress::WithContext(AddressMode::NotSupported)),
-                (1, 0, 0b00) => {
-                    let data = self.buffer.as_ref();
-                    Ok(UnresolvedAddress::WithoutContext(AddressMode::FullInline(
-                        &data[start..][..16],
-                    )))
-                }
-                (1, 0, 0b01) => {
-                    let data = self.buffer.as_ref();
-                    Ok(UnresolvedAddress::WithoutContext(
-                        AddressMode::Multicast48bits(&data[start..][..6]),
-                    ))
+                (0, 1, 0b01) => {
+                    if let Some(id) = self.dst_context_id() {
+                        Ok(UnresolvedAddress::WithContext((
+                            id as usize,
+                            AddressMode::InLine64bits(&data[start..][..8]),
+                        )))
+                    } else {
+                        Err(Error)
+                    }
                 }
-                (1, 0, 0b10) => {
-                    let data = self.buffer.as_ref();
-                    Ok(UnresolvedAddress::WithoutContext(
-                        AddressMode::Multicast32bits(&data[start..][..4]),
-                    ))
+                (0, 1, 0b10) => {
+                    if let Some(id) = self.dst_context_id() {
+                        Ok(UnresolvedAddress::WithContext((
+                            id as usize,
+                            AddressMode::InLine16bits(&data[start..][..2]),
+                        )))
+                    } else {
+                        Err(Error)
+                    }
                 }
-                (1, 0, 0b11) => {
-                    let data = self.buffer.as_ref();
-                    Ok(UnresolvedAddress::WithoutContext(
-                        AddressMode::Multicast8bits(&data[start..][..1]),
-                    ))
+                (0, 1, 0b11) => {
+                    if let Some(id) = self.dst_context_id() {
+                        Ok(UnresolvedAddress::WithContext((
+                            id as usize,
+                            AddressMode::FullyElided,
+                        )))
+                    } else {
+                        Err(Error)
+                    }
                 }
-                (1, 1, 0b00) => Ok(UnresolvedAddress::WithContext(AddressMode::NotSupported)),
+                (1, 0, 0b00) => Ok(UnresolvedAddress::WithoutContext(AddressMode::FullInline(
+                    &data[start..][..16],
+                ))),
+                (1, 0, 0b01) => Ok(UnresolvedAddress::WithoutContext(
+                    AddressMode::Multicast48bits(&data[start..][..6]),
+                )),
+                (1, 0, 0b10) => Ok(UnresolvedAddress::WithoutContext(
+                    AddressMode::Multicast32bits(&data[start..][..4]),
+                )),
+                (1, 0, 0b11) => Ok(UnresolvedAddress::WithoutContext(
+                    AddressMode::Multicast8bits(&data[start..][..1]),
+                )),
+                (1, 1, 0b00) => Ok(UnresolvedAddress::WithContext((
+                    0,
+                    AddressMode::NotSupported,
+                ))),
                 (1, 1, 0b01 | 0b10 | 0b11) => Ok(UnresolvedAddress::Reserved),
                 _ => Err(Error),
             }
@@ -1086,6 +1184,7 @@ pub mod iphc {
             packet: &Packet<&T>,
             ll_src_addr: Option<LlAddress>,
             ll_dst_addr: Option<LlAddress>,
+            addr_context: &[AddressContext<'_>],
         ) -> Result<Self> {
             // Ensure basic accessors will work.
             packet.check_len()?;
@@ -1095,8 +1194,8 @@ pub mod iphc {
                 return Err(Error);
             }
 
-            let src_addr = packet.src_addr()?.resolve(ll_src_addr)?;
-            let dst_addr = packet.dst_addr()?.resolve(ll_dst_addr)?;
+            let src_addr = packet.src_addr()?.resolve(ll_src_addr, addr_context)?;
+            let dst_addr = packet.dst_addr()?.resolve(ll_dst_addr, addr_context)?;
 
             Ok(Self {
                 src_addr,
@@ -1293,11 +1392,17 @@ pub mod iphc {
 
             assert_eq!(
                 packet.src_addr(),
-                Ok(UnresolvedAddress::WithContext(AddressMode::NotSupported))
+                Ok(UnresolvedAddress::WithContext((
+                    0,
+                    AddressMode::FullyElided
+                )))
             );
             assert_eq!(
                 packet.dst_addr(),
-                Ok(UnresolvedAddress::WithContext(AddressMode::NotSupported))
+                Ok(UnresolvedAddress::WithContext((
+                    0,
+                    AddressMode::FullyElided
+                )))
             );
         }
     }
@@ -2205,8 +2310,13 @@ mod test {
             unreachable!()
         };
 
-        let iphc_repr =
-            iphc::Repr::parse(&iphc, ieee802154_repr.src_addr, ieee802154_repr.dst_addr).unwrap();
+        let iphc_repr = iphc::Repr::parse(
+            &iphc,
+            ieee802154_repr.src_addr,
+            ieee802154_repr.dst_addr,
+            &[],
+        )
+        .unwrap();
 
         assert_eq!(
             iphc_repr.dst_addr,