add addr resolv with context

This commit is contained in:
Thibaut Vandervelden 2022-09-30 14:57:58 +02:00
parent fc69cdbe3c
commit d2e8e993fe
4 changed files with 220 additions and 79 deletions

View File

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

View File

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

View File

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

View File

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