Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove ieee802154 from IphcRepr #1033

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
55 changes: 35 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 @@ -744,8 +748,11 @@ fn decompress_ext_hdr<'d>(
}

// NOTE: we always inline this function into the sixlowpan_to_ipv6 function, since it is only used there.
#[allow(clippy::too_many_arguments)]
#[inline(always)]
fn decompress_udp(
address_context: &[SixlowpanAddressContext],
ieee802154_repr: &Ieee802154Repr,
data: &[u8],
iphc_repr: &SixlowpanIphcRepr,
buffer: &mut [u8],
Expand All @@ -757,8 +764,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
Loading