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,
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[..]);

View File

@ -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();

View File

@ -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")]

View File

@ -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(
(0, 0b00) => Ok(UnresolvedAddress::WithoutContext(AddressMode::FullInline(
&data[start..][..16],
)))
}
(0, 0b01) => {
let data = self.buffer.as_ref();
Ok(UnresolvedAddress::WithoutContext(
))),
(0, 0b01) => Ok(UnresolvedAddress::WithoutContext(
AddressMode::InLine64bits(&data[start..][..8]),
))
}
(0, 0b10) => {
let data = self.buffer.as_ref();
Ok(UnresolvedAddress::WithoutContext(
)),
(0, 0b10) => Ok(UnresolvedAddress::WithoutContext(
AddressMode::InLine16bits(&data[start..][..2]),
))
}
)),
(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)),
(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)
}
}
(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),
}
}
@ -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(
(0, 0, 0b00) => Ok(UnresolvedAddress::WithoutContext(AddressMode::FullInline(
&data[start..][..16],
)))
}
(0, 0, 0b01) => {
let data = self.buffer.as_ref();
Ok(UnresolvedAddress::WithoutContext(
))),
(0, 0, 0b01) => Ok(UnresolvedAddress::WithoutContext(
AddressMode::InLine64bits(&data[start..][..8]),
))
}
(0, 0, 0b10) => {
let data = self.buffer.as_ref();
Ok(UnresolvedAddress::WithoutContext(
)),
(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],
(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, 0b01) => {
let data = self.buffer.as_ref();
Ok(UnresolvedAddress::WithoutContext(
}
(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)
}
}
(0, 1, 0b11) => {
if let Some(id) = self.dst_context_id() {
Ok(UnresolvedAddress::WithContext((
id as usize,
AddressMode::FullyElided,
)))
} else {
Err(Error)
}
}
(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) => {
let data = self.buffer.as_ref();
Ok(UnresolvedAddress::WithoutContext(
)),
(1, 0, 0b10) => Ok(UnresolvedAddress::WithoutContext(
AddressMode::Multicast32bits(&data[start..][..4]),
))
}
(1, 0, 0b11) => {
let data = self.buffer.as_ref();
Ok(UnresolvedAddress::WithoutContext(
)),
(1, 0, 0b11) => Ok(UnresolvedAddress::WithoutContext(
AddressMode::Multicast8bits(&data[start..][..1]),
))
}
(1, 1, 0b00) => Ok(UnresolvedAddress::WithContext(AddressMode::NotSupported)),
)),
(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,