Skip to content

Commit

Permalink
Remove ieee802154 from IphcRepr
Browse files Browse the repository at this point in the history
  • Loading branch information
Dominic Fischer committed Jan 15, 2025
1 parent 74bd1e5 commit 8abb588
Show file tree
Hide file tree
Showing 7 changed files with 765 additions and 269 deletions.
42 changes: 20 additions & 22 deletions fuzz/fuzz_targets/sixlowpan_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,10 @@ fuzz_target!(|fuzz: SixlowpanPacketFuzzer| {
}
Ok(SixlowpanPacket::IphcHeader) => {
if let Ok(frame) = SixlowpanIphcPacket::new_checked(fuzz.data) {
if let Ok(iphc_repr) = SixlowpanIphcRepr::parse(
&frame,
fuzz.ll_src_addr.map(Into::into),
fuzz.ll_dst_addr.map(Into::into),
&[],
) {
if let Ok(iphc_repr) = SixlowpanIphcRepr::parse(&frame) {
let src_addr = iphc_repr.src_addr.resolve(fuzz.ll_src_addr.map(Into::into), &[], iphc_repr.context_identifier).unwrap();
let dst_addr = iphc_repr.dst_addr.resolve(fuzz.ll_dst_addr.map(Into::into), &[], iphc_repr.context_identifier).unwrap();

let mut buffer = vec![0; iphc_repr.buffer_len()];
let mut iphc_frame = SixlowpanIphcPacket::new_unchecked(&mut buffer[..]);
iphc_repr.emit(&mut iphc_frame);
Expand Down Expand Up @@ -75,8 +73,8 @@ fuzz_target!(|fuzz: SixlowpanPacketFuzzer| {
{
if let Ok(repr) = SixlowpanUdpNhcRepr::parse(
&frame,
&iphc_repr.src_addr,
&iphc_repr.dst_addr,
&src_addr,
&dst_addr,
&Default::default(),
) {
let mut buffer = vec![
Expand All @@ -90,8 +88,8 @@ fuzz_target!(|fuzz: SixlowpanPacketFuzzer| {
);
repr.emit(
&mut udp_packet,
&iphc_repr.src_addr,
&iphc_repr.dst_addr,
&src_addr,
&dst_addr,
frame.payload().len(),
|b| b.copy_from_slice(frame.payload()),
&ChecksumCapabilities::ignored(),
Expand Down Expand Up @@ -141,16 +139,16 @@ fuzz_target!(|fuzz: SixlowpanPacketFuzzer| {
if let Ok(frame) = TcpPacket::new_checked(payload) {
if let Ok(repr) = TcpRepr::parse(
&frame,
&iphc_repr.src_addr.into_address(),
&iphc_repr.dst_addr.into_address(),
&src_addr.into_address(),
&dst_addr.into_address(),
&ChecksumCapabilities::default(),
) {
let mut buffer = vec![0; repr.buffer_len()];
let mut frame = TcpPacket::new_unchecked(&mut buffer[..]);
repr.emit(
&mut frame,
&iphc_repr.src_addr.into_address(),
&iphc_repr.dst_addr.into_address(),
&src_addr.into_address(),
&dst_addr.into_address(),
&ChecksumCapabilities::default(),
);
}
Expand All @@ -160,17 +158,17 @@ fuzz_target!(|fuzz: SixlowpanPacketFuzzer| {
if let Ok(frame) = UdpPacket::new_checked(payload) {
if let Ok(repr) = UdpRepr::parse(
&frame,
&iphc_repr.src_addr.into_address(),
&iphc_repr.dst_addr.into_address(),
&src_addr.into_address(),
&dst_addr.into_address(),
&ChecksumCapabilities::default(),
) {
let mut buffer =
vec![0; repr.header_len() + frame.payload().len()];
let mut packet = UdpPacket::new_unchecked(&mut buffer[..]);
repr.emit(
&mut packet,
&iphc_repr.src_addr.into_address(),
&iphc_repr.dst_addr.into_address(),
&src_addr.into_address(),
&dst_addr.into_address(),
frame.payload().len(),
|b| b.copy_from_slice(frame.payload()),
&ChecksumCapabilities::default(),
Expand Down Expand Up @@ -200,17 +198,17 @@ fuzz_target!(|fuzz: SixlowpanPacketFuzzer| {
IpProtocol::Icmpv6 => {
if let Ok(packet) = Icmpv6Packet::new_checked(payload) {
if let Ok(repr) = Icmpv6Repr::parse(
&iphc_repr.src_addr.into_address(),
&iphc_repr.dst_addr.into_address(),
&src_addr.into_address(),
&dst_addr.into_address(),
&packet,
&ChecksumCapabilities::default(),
) {
let mut buffer = vec![0; repr.buffer_len()];
let mut packet =
Icmpv6Packet::new_unchecked(&mut buffer[..]);
repr.emit(
&iphc_repr.src_addr.into_address(),
&iphc_repr.dst_addr.into_address(),
&src_addr.into_address(),
&dst_addr.into_address(),
&mut packet,
&ChecksumCapabilities::default(),
);
Expand Down
54 changes: 34 additions & 20 deletions src/iface/interface/sixlowpan.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::*;
use crate::wire::ieee802154::{compress_destination_address, compress_source_address};
use crate::wire::Result;

// Max len of non-fragmented packets after decompression (including ipv6 header and payload)
Expand Down Expand Up @@ -206,12 +207,7 @@ impl InterfaceInner {
buffer: &mut [u8],
) -> Result<usize> {
let iphc = SixlowpanIphcPacket::new_checked(iphc_payload)?;
let iphc_repr = SixlowpanIphcRepr::parse(
&iphc,
ieee802154_repr.src_addr,
ieee802154_repr.dst_addr,
address_context,
)?;
let iphc_repr = SixlowpanIphcRepr::parse(&iphc)?;

// The first thing we have to decompress is the IPv6 header. However, at this point we
// don't know the total size of the packet, neither the next header, since that can be a
Expand Down Expand Up @@ -245,6 +241,8 @@ impl InterfaceInner {
}
SixlowpanNhcPacket::UdpHeader => {
decompress_udp(
address_context,
ieee802154_repr,
data,
&iphc_repr,
buffer,
Expand Down Expand Up @@ -282,8 +280,16 @@ impl InterfaceInner {
}

let ipv6_repr = Ipv6Repr {
src_addr: iphc_repr.src_addr,
dst_addr: iphc_repr.dst_addr,
src_addr: iphc_repr.src_addr.resolve(
ieee802154_repr.src_addr,
address_context,
iphc_repr.context_identifier,
)?,
dst_addr: iphc_repr.dst_addr.resolve(
ieee802154_repr.dst_addr,
address_context,
iphc_repr.context_identifier,
)?,
next_header: decompress_next_header(iphc_repr.next_header, iphc.payload())?,
payload_len: total_len.unwrap_or(payload_len) - 40,
hop_limit: iphc_repr.hop_limit,
Expand Down Expand Up @@ -446,10 +452,9 @@ impl InterfaceInner {
};

let iphc_repr = SixlowpanIphcRepr {
src_addr: packet.header.src_addr,
ll_src_addr: ieee_repr.src_addr,
dst_addr: packet.header.dst_addr,
ll_dst_addr: ieee_repr.dst_addr,
src_addr: compress_source_address(packet.header.src_addr, ieee_repr.src_addr),
dst_addr: compress_destination_address(packet.header.dst_addr, ieee_repr.dst_addr),
context_identifier: None,
next_header,
hop_limit: packet.header.hop_limit,
ecn: None,
Expand Down Expand Up @@ -529,8 +534,8 @@ impl InterfaceInner {
&mut SixlowpanUdpNhcPacket::new_unchecked(
&mut buffer[..udp_repr.header_len() + payload.len()],
),
&iphc_repr.src_addr,
&iphc_repr.dst_addr,
&packet.header.src_addr,
&packet.header.dst_addr,
payload.len(),
|buf| buf.copy_from_slice(payload),
checksum_caps,
Expand Down Expand Up @@ -581,10 +586,9 @@ impl InterfaceInner {
};

let iphc = SixlowpanIphcRepr {
src_addr: packet.header.src_addr,
ll_src_addr: ieee_repr.src_addr,
dst_addr: packet.header.dst_addr,
ll_dst_addr: ieee_repr.dst_addr,
src_addr: compress_source_address(packet.header.src_addr, ieee_repr.src_addr),
dst_addr: compress_destination_address(packet.header.dst_addr, ieee_repr.dst_addr),
context_identifier: None,
next_header,
hop_limit: packet.header.hop_limit,
ecn: None,
Expand Down Expand Up @@ -746,6 +750,8 @@ fn decompress_ext_hdr<'d>(
// NOTE: we always inline this function into the sixlowpan_to_ipv6 function, since it is only used there.
#[inline(always)]
fn decompress_udp(
address_context: &[SixlowpanAddressContext],
ieee802154_repr: &Ieee802154Repr,
data: &[u8],
iphc_repr: &SixlowpanIphcRepr,
buffer: &mut [u8],
Expand All @@ -757,8 +763,16 @@ fn decompress_udp(
let payload = udp_packet.payload();
let udp_repr = SixlowpanUdpNhcRepr::parse(
&udp_packet,
&iphc_repr.src_addr,
&iphc_repr.dst_addr,
&iphc_repr.src_addr.resolve(
ieee802154_repr.src_addr,
address_context,
iphc_repr.context_identifier,
)?,
&iphc_repr.dst_addr.resolve(
ieee802154_repr.dst_addr,
address_context,
iphc_repr.context_identifier,
)?,
&ChecksumCapabilities::ignored(),
)?;
if udp_repr.header_len() + payload.len() > buffer.len() {
Expand Down
27 changes: 18 additions & 9 deletions src/iface/interface/tests/sixlowpan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,20 +138,29 @@ fn test_echo_request_sixlowpan_128_bytes() {
let request_first_part_iphc_packet =
SixlowpanIphcPacket::new_checked(request_first_part_packet.payload()).unwrap();

let request_first_part_iphc_repr = SixlowpanIphcRepr::parse(
&request_first_part_iphc_packet,
ieee802154_repr.src_addr,
ieee802154_repr.dst_addr,
&iface.inner.sixlowpan_address_context,
)
.unwrap();
let request_first_part_iphc_repr =
SixlowpanIphcRepr::parse(&request_first_part_iphc_packet).unwrap();

assert_eq!(
request_first_part_iphc_repr.src_addr,
request_first_part_iphc_repr
.src_addr
.resolve(
ieee802154_repr.src_addr,
&iface.inner.sixlowpan_address_context,
request_first_part_iphc_repr.context_identifier
)
.unwrap(),
Ipv6Address::new(0xfe80, 0, 0, 0, 0x4042, 0x4242, 0x4242, 0x0b1a),
);
assert_eq!(
request_first_part_iphc_repr.dst_addr,
request_first_part_iphc_repr
.dst_addr
.resolve(
ieee802154_repr.dst_addr,
&iface.inner.sixlowpan_address_context,
request_first_part_iphc_repr.context_identifier
)
.unwrap(),
Ipv6Address::new(0xfe80, 0, 0, 0, 0x92fc, 0x48c2, 0xa441, 0xfc76),
);

Expand Down
104 changes: 103 additions & 1 deletion src/wire/ieee802154.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ use core::fmt;

use byteorder::{ByteOrder, LittleEndian};

use super::{Error, Result};
use super::{ipv6, Error, Result};
use crate::wire::sixlowpan::{
DestinationAddress, LinkLocalAddress, MulticastAddress, SourceAddress,
};
use crate::wire::{Ipv6Address, Ipv6AddressExt};

enum_with_unknown! {
Expand Down Expand Up @@ -1006,6 +1009,105 @@ impl Repr {
}
}

pub fn compress_source_address(
src_addr: ipv6::Address,
ll_src_addr: Option<Address>,
) -> SourceAddress {
let src = src_addr.octets();

if src_addr == ipv6::Address::UNSPECIFIED {
SourceAddress::Unspecified
} else if src_addr.is_link_local() {
// We have a link local address.
// The remainder of the address can be elided when the context contains
// a 802.15.4 short address or a 802.15.4 extended address which can be
// converted to a eui64 address.
let is_eui_64 = ll_src_addr
.map(|addr| {
addr.as_eui_64()
.map(|addr| addr[..] == src[8..])
.unwrap_or(false)
})
.unwrap_or(false);

if src[8..14] == [0, 0, 0, 0xff, 0xfe, 0] {
let ll = [src[14], src[15]];

if ll_src_addr == Some(crate::wire::ieee802154::Address::Short(ll)) {
// We have the context from the 802.15.4 frame.
// The context contains the short address.
// We can elide the source address.
SourceAddress::LinkLocal(LinkLocalAddress::FullyElided)
} else {
// We don't have the context from the 802.15.4 frame.
// We cannot elide the source address, however we can elide 112 bits.
SourceAddress::LinkLocal(LinkLocalAddress::InLine16bits(
src[14..].try_into().unwrap(),
))
}
} else if is_eui_64 {
// We have the context from the 802.15.4 frame.
// The context contains the extended address.
// We can elide the source address.
SourceAddress::LinkLocal(LinkLocalAddress::FullyElided)
} else {
// We cannot elide the source address, however we can elide 64 bits.
SourceAddress::LinkLocal(LinkLocalAddress::InLine64bits(src[8..].try_into().unwrap()))
}
} else {
// We cannot elide anything.
SourceAddress::LinkLocal(LinkLocalAddress::InLine128bits(src))
}
}

pub fn compress_destination_address(
dst_addr: ipv6::Address,
ll_dst_addr: Option<Address>,
) -> DestinationAddress {
let dst = dst_addr.octets();
if dst_addr.is_multicast() {
if dst[1] == 0x02 && dst[2..15] == [0; 13] {
DestinationAddress::Multicast(MulticastAddress::Inline8bits(dst[15]))
} else if dst[2..13] == [0; 11] {
let address = [dst[1], dst[13], dst[14], dst[15]];
DestinationAddress::Multicast(MulticastAddress::Inline32bits(address))
} else if dst[2..11] == [0; 9] {
let address = [dst[1], dst[11], dst[12], dst[13], dst[14], dst[15]];
DestinationAddress::Multicast(MulticastAddress::Inline48bits(address))
} else {
DestinationAddress::Multicast(MulticastAddress::FullInline(dst))
}
} else if dst_addr.is_link_local() {
let is_eui_64 = ll_dst_addr
.map(|addr| {
addr.as_eui_64()
.map(|addr| addr[..] == dst[8..])
.unwrap_or(false)
})
.unwrap_or(false);

if dst[8..14] == [0, 0, 0, 0xff, 0xfe, 0] {
let ll = [dst[14], dst[15]];

if ll_dst_addr == Some(crate::wire::ieee802154::Address::Short(ll)) {
DestinationAddress::LinkLocal(LinkLocalAddress::FullyElided)
} else {
DestinationAddress::LinkLocal(LinkLocalAddress::InLine16bits(
dst[14..].try_into().unwrap(),
))
}
} else if is_eui_64 {
DestinationAddress::LinkLocal(LinkLocalAddress::FullyElided)
} else {
DestinationAddress::LinkLocal(LinkLocalAddress::InLine64bits(
dst[8..].try_into().unwrap(),
))
}
} else {
DestinationAddress::LinkLocal(LinkLocalAddress::InLine128bits(dst))
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
Loading

0 comments on commit 8abb588

Please sign in to comment.